HID-PTS:Included API and calbabkcs for hid pts tests
Change-Id: I7f3b19dbcda24dbb0cd4700a54f7cd05e84d3745
diff --git a/jni/com_android_bluetooth_hid.cpp b/jni/com_android_bluetooth_hid.cpp
index cae1056..d0c178d 100755
--- a/jni/com_android_bluetooth_hid.cpp
+++ b/jni/com_android_bluetooth_hid.cpp
@@ -22,6 +22,9 @@
namespace android {
static jmethodID method_onConnectStateChanged;
+static jmethodID method_onGetProtocolMode;
+static jmethodID method_onGetReport;
+static jmethodID method_onVirtualUnplug;
static const bthh_interface_t *sBluetoothHidInterface = NULL;
static jobject mCallbacksObj = NULL;
@@ -58,14 +61,71 @@
sCallbackEnv->DeleteLocalRef(addr);
}
+static void get_protocol_mode_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,bthh_protocol_mode_t mode) {
+ jbyteArray addr;
+
+ CHECK_CALLBACK_ENV
+ if (hh_status != BTHH_OK) {
+ LOGE("BTHH Status is not OK!");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ LOGE("Fail to new jbyteArray bd addr for get protocal mode callback");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
+
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetProtocolMode, addr, (jint) mode);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
+}
+
+static void virtual_unplug_callback(bt_bdaddr_t *bd_addr, bthh_status_t hh_status) {
+ LOGD("call to virtual_unplug_callback");
+ jbyteArray addr;
+
+ CHECK_CALLBACK_ENV
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ LOGE("Fail to new jbyteArray bd addr for HID channel state");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
+
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, (jint) hh_status);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
+
+ /*jbyteArray addr;
+ jint status = hh_status;
+ CHECK_CALLBACK_ENV
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ LOGE("Fail to new jbyteArray bd addr for HID report");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
+
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug, addr, status);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);*/
+}
+
+
static bthh_callbacks_t sBluetoothHidCallbacks = {
sizeof(sBluetoothHidCallbacks),
connection_state_callback,
NULL,
+ get_protocol_mode_callback,
NULL,
NULL,
- NULL,
- NULL
+ virtual_unplug_callback
};
// Define native functions
@@ -75,8 +135,9 @@
const bt_interface_t* btInf;
bt_status_t status;
- method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged",
- "([BI)V");
+ method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V");
+ method_onGetProtocolMode = env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V");
+ method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V");
if ( (btInf = getBluetoothInterface()) == NULL) {
LOGE("Bluetooth module is not loaded");
@@ -149,12 +210,177 @@
return ret;
}
+static jboolean getProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address) {
+ bt_status_t status;
+ jbyte *addr;
+ jboolean ret = JNI_TRUE;
+ bthh_protocol_mode_t protocolMode;
+ if (!sBluetoothHidInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ LOGE("Bluetooth device address null");
+ return JNI_FALSE;
+ }
+
+ if ( (status = sBluetoothHidInterface->get_protocol((bt_bdaddr_t *) addr, (bthh_protocol_mode_t) protocolMode)) !=
+ BT_STATUS_SUCCESS) {
+ LOGE("Failed get protocol mode, status: %d", status);
+ ret = JNI_FALSE;
+ }
+ env->ReleaseByteArrayElements(address, addr, 0);
+
+ return ret;
+}
+
+static jboolean virtualUnPlugNative(JNIEnv *env, jobject object, jbyteArray address) {
+ bt_status_t status;
+ jbyte *addr;
+ jboolean ret = JNI_TRUE;
+ if (!sBluetoothHidInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ LOGE("Bluetooth device address null");
+ return JNI_FALSE;
+ }
+ if ( (status = sBluetoothHidInterface->virtual_unplug((bt_bdaddr_t *) addr)) !=
+ BT_STATUS_SUCCESS) {
+ LOGE("Failed virual unplug, status: %d", status);
+ ret = JNI_FALSE;
+ }
+ env->ReleaseByteArrayElements(address, addr, 0);
+ return ret;
+
+}
+
+
+static jboolean setProtocolModeNative(JNIEnv *env, jobject object, jbyteArray address, jint protocolMode) {
+ bt_status_t status;
+ jbyte *addr;
+ jboolean ret = JNI_TRUE;
+ if (!sBluetoothHidInterface) return JNI_FALSE;
+
+ LOGD("%s: protocolMode = %d", __FUNCTION__, protocolMode);
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ LOGE("Bluetooth device address null");
+ return JNI_FALSE;
+ }
+
+ bthh_protocol_mode_t mode;
+ switch(protocolMode){
+ case 0:
+ mode = BTHH_REPORT_MODE;
+ break;
+ case 1:
+ mode = BTHH_BOOT_MODE;
+ break;
+ default:
+ LOGE("Unknown HID protocol mode");
+ return JNI_FALSE;
+ }
+ if ( (status = sBluetoothHidInterface->set_protocol((bt_bdaddr_t *) addr, mode)) !=
+ BT_STATUS_SUCCESS) {
+ LOGE("Failed set protocol mode, status: %d", status);
+ ret = JNI_FALSE;
+ }
+ env->ReleaseByteArrayElements(address, addr, 0);
+
+ return JNI_TRUE;
+}
+
+static jboolean getReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jbyte reportId, jint bufferSize) {
+ LOGD("%s: reportType = %d, reportId = %d, bufferSize = %d", __FUNCTION__, reportType, reportId, bufferSize);
+
+ bt_status_t status;
+ jbyte *addr;
+ jboolean ret = JNI_TRUE;
+ if (!sBluetoothHidInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ LOGE("Bluetooth device address null");
+ return JNI_FALSE;
+ }
+
+ jint rType = reportType;
+ jint rId = reportId;
+
+ if ( (status = sBluetoothHidInterface->get_report((bt_bdaddr_t *) addr, (bthh_report_type_t) rType, (uint8_t) rId, bufferSize)) !=
+ BT_STATUS_SUCCESS) {
+ LOGE("Failed get report, status: %d", status);
+ ret = JNI_FALSE;
+ }
+ env->ReleaseByteArrayElements(address, addr, 0);
+
+ return ret;
+}
+
+
+static jboolean setReportNative(JNIEnv *env, jobject object, jbyteArray address, jbyte reportType, jstring report) {
+ LOGD("%s: reportType = %d", __FUNCTION__, reportType);
+ bt_status_t status;
+ jbyte *addr;
+ jboolean ret = JNI_TRUE;
+ if (!sBluetoothHidInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ LOGE("Bluetooth device address null");
+ return JNI_FALSE;
+ }
+ jint rType = reportType;
+ const char *c_report = env->GetStringUTFChars(report, NULL);
+
+ if ( (status = sBluetoothHidInterface->set_report((bt_bdaddr_t *) addr, (bthh_report_type_t)rType, (char*) c_report)) !=
+ BT_STATUS_SUCCESS) {
+ LOGE("Failed set report, status: %d", status);
+ ret = JNI_FALSE;
+ }
+ env->ReleaseStringUTFChars(report, c_report);
+ env->ReleaseByteArrayElements(address, addr, 0);
+
+ return ret;
+}
+
+static jboolean sendDataNative(JNIEnv *env, jobject object, jbyteArray address, jstring report) {
+ LOGD("%s", __FUNCTION__);
+ bt_status_t status;
+ jbyte *addr;
+ jboolean ret = JNI_TRUE;
+ if (!sBluetoothHidInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ LOGE("Bluetooth device address null");
+ return JNI_FALSE;
+ }
+ const char *c_report = env->GetStringUTFChars(report, NULL);
+ if ( (status = sBluetoothHidInterface->send_data((bt_bdaddr_t *) addr, (char*) c_report)) !=
+ BT_STATUS_SUCCESS) {
+ LOGE("Failed set report, status: %d", status);
+ ret = JNI_FALSE;
+ }
+ env->ReleaseStringUTFChars(report, c_report);
+ env->ReleaseByteArrayElements(address, addr, 0);
+
+ return ret;
+
+}
+
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void *) classInitNative},
{"initializeNativeDataNative", "()V", (void *) initializeNativeDataNative},
{"connectHidNative", "([B)Z", (void *) connectHidNative},
{"disconnectHidNative", "([B)Z", (void *) disconnectHidNative},
- // TBD
+ {"getProtocolModeNative", "([B)Z", (void *) getProtocolModeNative},
+ {"virtualUnPlugNative", "([B)Z", (void *) virtualUnPlugNative},
+ {"setProtocolModeNative", "([BB)Z", (void *) setProtocolModeNative},
+ {"getReportNative", "([BBBI)Z", (void *) getReportNative},
+ {"setReportNative", "([BBLjava/lang/String;)Z", (void *) setReportNative},
+ {"sendDataNative", "([BLjava/lang/String;)Z", (void *) sendDataNative},
};
int register_com_android_bluetooth_hid(JNIEnv* env)
diff --git a/src/com/android/bluetooth/hid/HidService.java b/src/com/android/bluetooth/hid/HidService.java
old mode 100644
new mode 100755
index bc432be..2bf580f
--- a/src/com/android/bluetooth/hid/HidService.java
+++ b/src/com/android/bluetooth/hid/HidService.java
@@ -12,6 +12,7 @@
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothInputDevice;
import android.content.Intent;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Handler;
import android.os.Message;
@@ -46,6 +47,15 @@
private static final int MESSAGE_CONNECT = 1;
private static final int MESSAGE_DISCONNECT = 2;
private static final int MESSAGE_CONNECT_STATE_CHANGED = 3;
+ private static final int MESSAGE_GET_PROTOCOL_MODE = 4;
+ private static final int MESSAGE_VIRTUAL_UNPLUG = 5;
+ private static final int MESSAGE_ON_GET_PROTOCOL_MODE = 6;
+ private static final int MESSAGE_SET_PROTOCOL_MODE = 7;
+ private static final int MESSAGE_GET_REPORT = 8;
+ private static final int MESSAGE_ON_GET_REPORT = 9;
+ private static final int MESSAGE_SET_REPORT = 10;
+ private static final int MESSAGE_SEND_DATA = 11;
+ private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12;
static {
classInitNative();
@@ -113,6 +123,80 @@
broadcastConnectionState(device, convertHalState(halState));
}
break;
+ case MESSAGE_GET_PROTOCOL_MODE:
+ {
+ BluetoothDevice device = (BluetoothDevice) msg.obj;
+ if(!getProtocolModeNative(getByteAddress(device)) ) {
+ Log.e(TAG, "Error: get protocol mode native returns false");
+ }
+ }
+ break;
+
+ case MESSAGE_ON_GET_PROTOCOL_MODE:
+ {
+ BluetoothDevice device = getDevice((byte[]) msg.obj);
+ int protocolMode = msg.arg1;
+ broadcastProtocolMode(device, protocolMode);
+ }
+ break;
+ case MESSAGE_VIRTUAL_UNPLUG:
+ {
+ BluetoothDevice device = (BluetoothDevice) msg.obj;
+ if(!virtualUnPlugNative(getByteAddress(device))) {
+ Log.e(TAG, "Error: virtual unplug native returns false");
+ }
+ }
+ break;
+ case MESSAGE_SET_PROTOCOL_MODE:
+ {
+ BluetoothDevice device = (BluetoothDevice) msg.obj;
+ byte protocolMode = (byte) msg.arg1;
+ log("sending set protocol mode(" + protocolMode + ")");
+ if(!setProtocolModeNative(getByteAddress(device), protocolMode)) {
+ Log.e(TAG, "Error: set protocol mode native returns false");
+ }
+ }
+ break;
+ case MESSAGE_GET_REPORT:
+ {
+ BluetoothDevice device = (BluetoothDevice) msg.obj;
+ Bundle data = msg.getData();
+ byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE);
+ byte reportId = data.getByte(BluetoothInputDevice.EXTRA_REPORT_ID);
+ int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE);
+ if(!getReportNative(getByteAddress(device), reportType, reportId, bufferSize)) {
+ Log.e(TAG, "Error: get report native returns false");
+ }
+ }
+ break;
+ case MESSAGE_SET_REPORT:
+ {
+ BluetoothDevice device = (BluetoothDevice) msg.obj;
+ Bundle data = msg.getData();
+ byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE);
+ String report = data.getString(BluetoothInputDevice.EXTRA_REPORT);
+ if(!setReportNative(getByteAddress(device), reportType, report)) {
+ Log.e(TAG, "Error: set report native returns false");
+ }
+ }
+ break;
+ case MESSAGE_SEND_DATA:
+ {
+ BluetoothDevice device = (BluetoothDevice) msg.obj;
+ Bundle data = msg.getData();
+ String report = data.getString(BluetoothInputDevice.EXTRA_REPORT);
+ if(!sendDataNative(getByteAddress(device), report)) {
+ Log.e(TAG, "Error: send data native returns false");
+ }
+ }
+ break;
+ case MESSAGE_ON_VIRTUAL_UNPLUG:
+ {
+ BluetoothDevice device = getDevice((byte[]) msg.obj);
+ int status = msg.arg1;
+ broadcastVirtualUnplugStatus(device, status);
+ }
+ break;
}
}
};
@@ -195,8 +279,118 @@
return priority;
}
+ public boolean getProtocolMode(BluetoothDevice device) {
+ enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ int state = this.getConnectionState(device);
+ if (state != BluetoothInputDevice.STATE_CONNECTED) {
+ return false;
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_GET_PROTOCOL_MODE);
+ msg.obj = device;
+ mHandler.sendMessage(msg);
+ return true;
+ /* String objectPath = getObjectPathFromAddress(device.getAddress());
+ return getProtocolModeInputDeviceNative(objectPath);*/
+ }
+
+ public boolean virtualUnplug(BluetoothDevice device) {
+ enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ int state = this.getConnectionState(device);
+ if (state != BluetoothInputDevice.STATE_CONNECTED) {
+ return false;
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_VIRTUAL_UNPLUG);
+ msg.obj = device;
+ mHandler.sendMessage(msg);
+
+ return true;
+ }
+
+ public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
+ enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ int state = this.getConnectionState(device);
+ if (state != BluetoothInputDevice.STATE_CONNECTED) {
+ return false;
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL_MODE);
+ msg.obj = device;
+ msg.arg1 = protocolMode;
+ mHandler.sendMessage(msg);
+ return true ;
+ }
+
+ public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
+ enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ int state = this.getConnectionState(device);
+ if (state != BluetoothInputDevice.STATE_CONNECTED) {
+ return false;
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT);
+ msg.obj = device;
+ Bundle data = new Bundle();
+ data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType);
+ data.putByte(BluetoothInputDevice.EXTRA_REPORT_ID, reportId);
+ data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, bufferSize);
+ msg.setData(data);
+ mHandler.sendMessage(msg);
+ return true ;
+ }
+
+ public boolean setReport(BluetoothDevice device, byte reportType, String report) {
+ enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ int state = this.getConnectionState(device);
+ if (state != BluetoothInputDevice.STATE_CONNECTED) {
+ return false;
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT);
+ msg.obj = device;
+ Bundle data = new Bundle();
+ data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType);
+ data.putString(BluetoothInputDevice.EXTRA_REPORT, report);
+ msg.setData(data);
+ mHandler.sendMessage(msg);
+ return true ;
+
+ }
+
+ public boolean sendData(BluetoothDevice device, String report) {
+ enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ int state = this.getConnectionState(device);
+ if (state != BluetoothInputDevice.STATE_CONNECTED) {
+ return false;
+ }
+
+ return sendDataNative(getByteAddress(device), report);
+ /*Message msg = mHandler.obtainMessage(MESSAGE_SEND_DATA);
+ msg.obj = device;
+ Bundle data = new Bundle();
+ data.putString(BluetoothInputDevice.EXTRA_REPORT, report);
+ msg.setData(data);
+ mHandler.sendMessage(msg);
+ return true ;*/
+ }
};
+ private void onGetProtocolMode(byte[] address, int mode) {
+ Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_PROTOCOL_MODE);
+ msg.obj = address;
+ msg.arg1 = mode;
+ mHandler.sendMessage(msg);
+ }
+
+ private void onVirtualUnplug(byte[] address, int status) {
+ Message msg = mHandler.obtainMessage(MESSAGE_ON_VIRTUAL_UNPLUG);
+ msg.obj = address;
+ msg.arg1 = status;
+ mHandler.sendMessage(msg);
+ }
+
private void onConnectStateChanged(byte[] address, int state) {
Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED);
msg.obj = address;
@@ -230,6 +424,23 @@
}
}
+ private void broadcastProtocolMode(BluetoothDevice device, int protocolMode) {
+ Intent intent = new Intent(BluetoothInputDevice.ACTION_PROTOCOL_MODE_CHANGED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ intent.putExtra(BluetoothInputDevice.EXTRA_PROTOCOL_MODE, protocolMode);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ sendBroadcast(intent, BLUETOOTH_PERM);
+ if (DBG) log("Protocol Mode (" + device + "): " + protocolMode);
+ }
+
+ private void broadcastVirtualUnplugStatus(BluetoothDevice device, int status) {
+ Intent intent = new Intent(BluetoothInputDevice.ACTION_VIRTUAL_UNPLUG_STATUS);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ intent.putExtra(BluetoothInputDevice.EXTRA_VIRTUAL_UNPLUG_STATUS, status);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+
private BluetoothDevice getDevice(byte[] address) {
return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
}
@@ -269,4 +480,10 @@
private native void initializeNativeDataNative();
private native boolean connectHidNative(byte[] btAddress);
private native boolean disconnectHidNative(byte[] btAddress);
+ private native boolean getProtocolModeNative(byte[] btAddress);
+ private native boolean virtualUnPlugNative(byte[] btAddress);
+ private native boolean setProtocolModeNative(byte[] btAddress, byte protocolMode);
+ private native boolean getReportNative(byte[]btAddress, byte reportType, byte reportId, int bufferSize);
+ private native boolean setReportNative(byte[] btAddress, byte reportType, String report);
+ private native boolean sendDataNative(byte[] btAddress, String report);
}