Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c390505 authored by Hemant Gupta's avatar Hemant Gupta Committed by Myles Watson
Browse files

HID: Add support for Set Idle and Get Idle commands (4/4)

Provides an interface for application to send Set Idle
and Get Idle commands to remote HID Device. Support for these
two commands was missing from existing code, so existing code
design is reused to add support for these two commands.

Without this support following mandatory PTS test cases for HID 1.0
cannot be passed, TC_HOS_HID_BV_05/06

Test: Executed PTS tests TC_HOS_HID_BV_05/06 and confirmed if they can
pass

Bug: 34344715
Change-Id: I066d47c022905a39c11d365a9d26d128f94fe2f6
parent bad40a0a
Loading
Loading
Loading
Loading
+59 −2
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ static jmethodID method_onGetProtocolMode;
static jmethodID method_onGetReport;
static jmethodID method_onHandshake;
static jmethodID method_onVirtualUnplug;
static jmethodID method_onGetIdleTime;

static const bthh_interface_t* sBluetoothHidInterface = NULL;
static jobject mCallbacksObj = NULL;
@@ -157,12 +158,26 @@ static void handshake_callback(bt_bdaddr_t* bd_addr, bthh_status_t hh_status) {
                               (jint)hh_status);
}

static void get_idle_time_callback(bt_bdaddr_t* bd_addr,
                                   bthh_status_t hh_status, int idle_time) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) {
    ALOGE("%s: Fail to new jbyteArray bd addr", __func__);
    return;
  }
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetIdleTime, addr.get(),
                               (jint)idle_time);
}

static bthh_callbacks_t sBluetoothHidCallbacks = {
    sizeof(sBluetoothHidCallbacks),
    connection_state_callback,
    NULL,
    get_protocol_mode_callback,
    NULL,
    get_idle_time_callback,
    get_report_callback,
    virtual_unplug_callback,
    handshake_callback};
@@ -177,6 +192,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
  method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V");
  method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V");
  method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V");
  method_onGetIdleTime = env->GetMethodID(clazz, "onGetIdleTime", "([BI)V");

  ALOGI("%s: succeeds", __func__);
}
@@ -434,7 +450,7 @@ static jboolean sendDataNative(JNIEnv* env, jobject object, jbyteArray address,
  bt_status_t status =
      sBluetoothHidInterface->send_data((bt_bdaddr_t*)addr, (char*)c_report);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("Failed set report, status: %d", status);
    ALOGE("Failed set data, status: %d", status);
    ret = JNI_FALSE;
  }
  env->ReleaseStringUTFChars(report, c_report);
@@ -443,6 +459,45 @@ static jboolean sendDataNative(JNIEnv* env, jobject object, jbyteArray address,
  return ret;
}

static jboolean getIdleTimeNative(JNIEnv* env, jobject object,
                                  jbyteArray address) {
  if (!sBluetoothHidInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
  if (!addr) {
    ALOGE("%s: Bluetooth device address null", __func__);
    return JNI_FALSE;
  }

  bt_status_t status = sBluetoothHidInterface->get_idle_time((bt_bdaddr_t*)addr);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("%s: Failed get idle time, status: %d", __func__, status);
  }
  env->ReleaseByteArrayElements(address, addr, 0);

  return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
}

static jboolean setIdleTimeNative(JNIEnv* env, jobject object,
                                  jbyteArray address, jbyte idle_time) {
  if (!sBluetoothHidInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
  if (!addr) {
    ALOGE("%s: Bluetooth device address null", __func__);
    return JNI_FALSE;
  }

  bt_status_t status = sBluetoothHidInterface->set_idle_time(
           (bt_bdaddr_t*)addr, idle_time);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("%s: Failed set idle time, status: %d", __func__, status);
  }
  env->ReleaseByteArrayElements(address, addr, 0);

  return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
}

static JNINativeMethod sMethods[] = {
    {"classInitNative", "()V", (void*)classInitNative},
    {"initializeNative", "()V", (void*)initializeNative},
@@ -455,6 +510,8 @@ static JNINativeMethod sMethods[] = {
    {"getReportNative", "([BBBI)Z", (void*)getReportNative},
    {"setReportNative", "([BBLjava/lang/String;)Z", (void*)setReportNative},
    {"sendDataNative", "([BLjava/lang/String;)Z", (void*)sendDataNative},
    {"getIdleTimeNative", "([B)Z", (void*)getIdleTimeNative},
    {"setIdleTimeNative", "([BB)Z", (void*)setIdleTimeNative},
};

int register_com_android_bluetooth_hid(JNIEnv* env) {
+78 −0
Original line number Diff line number Diff line
@@ -64,6 +64,9 @@ public class HidService extends ProfileService {
    private static final int MESSAGE_SEND_DATA = 11;
    private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12;
    private static final int MESSAGE_ON_HANDSHAKE = 13;
    private static final int MESSAGE_GET_IDLE_TIME = 14;
    private static final int MESSAGE_ON_GET_IDLE_TIME = 15;
    private static final int MESSAGE_SET_IDLE_TIME = 16;

    static {
        classInitNative();
@@ -287,6 +290,25 @@ public class HidService extends ProfileService {
                    broadcastVirtualUnplugStatus(device, status);
                }
                break;
                case MESSAGE_GET_IDLE_TIME: {
                    BluetoothDevice device = (BluetoothDevice) msg.obj;
                    if (!getIdleTimeNative(Utils.getByteAddress(device))) {
                        Log.e(TAG, "Error: get idle time native returns false");
                    }
                } break;
                case MESSAGE_ON_GET_IDLE_TIME: {
                    BluetoothDevice device = getDevice((byte[]) msg.obj);
                    int idleTime = msg.arg1;
                    broadcastIdleTime(device, idleTime);
                } break;
                case MESSAGE_SET_IDLE_TIME: {
                    BluetoothDevice device = (BluetoothDevice) msg.obj;
                    Bundle data = msg.getData();
                    byte idleTime = data.getByte(BluetoothInputDevice.EXTRA_IDLE_TIME);
                    if (!setIdleTimeNative(Utils.getByteAddress(device), idleTime)) {
                        Log.e(TAG, "Error: get idle time native returns false");
                    }
                } break;
            }
        }
    };
@@ -394,6 +416,18 @@ public class HidService extends ProfileService {
            if (service == null) return false;
            return service.sendData(device, report);
        }

        public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
            HidService service = getService();
            if (service == null) return false;
            return service.setIdleTime(device, idleTime);
        }

        public boolean getIdleTime(BluetoothDevice device) {
            HidService service = getService();
            if (service == null) return false;
            return service.getIdleTime(device);
        }
    };

    //APIs
@@ -550,6 +584,32 @@ public class HidService extends ProfileService {
        return sendDataNative(Utils.getByteAddress(device), report);
    }

    boolean getIdleTime(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_IDLE_TIME, device);
        mHandler.sendMessage(msg);
        return true;
    }

    boolean setIdleTime(BluetoothDevice device, byte idleTime) {
        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_IDLE_TIME);
        msg.obj = device;
        Bundle data = new Bundle();
        data.putByte(BluetoothInputDevice.EXTRA_IDLE_TIME, idleTime);
        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;
@@ -557,6 +617,13 @@ public class HidService extends ProfileService {
        mHandler.sendMessage(msg);
    }

    private void onGetIdleTime(byte[] address, int idleTime) {
        Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_IDLE_TIME);
        msg.obj = address;
        msg.arg1 = idleTime;
        mHandler.sendMessage(msg);
    }

    private void onGetReport(byte[] address, byte[] report, int rpt_size) {
        Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_REPORT);
        msg.obj = address;
@@ -645,6 +712,15 @@ public class HidService extends ProfileService {
        sendBroadcast(intent, BLUETOOTH_PERM);
    }

    private void broadcastIdleTime(BluetoothDevice device, int idleTime) {
        Intent intent = new Intent(BluetoothInputDevice.ACTION_IDLE_TIME_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothInputDevice.EXTRA_IDLE_TIME, idleTime);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        sendBroadcast(intent, BLUETOOTH_PERM);
        if (DBG) log("Idle time (" + device + "): " + idleTime);
    }

    private boolean okToConnect(BluetoothDevice device) {
        AdapterService adapterService = AdapterService.getAdapterService();
        //check if it is inbound connection in Quiet mode, priority and Bond status
@@ -701,4 +777,6 @@ public class HidService extends ProfileService {
    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);
    private native boolean setIdleTimeNative(byte[] btAddress, byte idleTime);
    private native boolean getIdleTimeNative(byte[] btAddress);
}