void
BluetoothGattServer::HandleReadWriteRequest(const BluetoothValue& aValue,
                                            const nsAString& aEventName)
{
  MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
  const InfallibleTArray<BluetoothNamedValue>& arr =
    aValue.get_ArrayOfBluetoothNamedValue();

  MOZ_ASSERT(arr.Length() == 5 &&
    arr[0].value().type() == BluetoothValue::Tint32_t &&
    arr[1].value().type() == BluetoothValue::TBluetoothAttributeHandle &&
    arr[2].value().type() == BluetoothValue::TnsString &&
    arr[3].value().type() == BluetoothValue::Tbool &&
    arr[4].value().type() == BluetoothValue::TArrayOfuint8_t);

  int32_t requestId = arr[0].value().get_int32_t();
  BluetoothAttributeHandle handle =
    arr[1].value().get_BluetoothAttributeHandle();
  nsString address = arr[2].value().get_nsString();
  bool needResponse = arr[3].value().get_bool();
  nsTArray<uint8_t> value;
  value = arr[4].value().get_ArrayOfuint8_t();

  // Find the target characteristic or descriptor from the given handle
  RefPtr<BluetoothGattCharacteristic> characteristic = nullptr;
  RefPtr<BluetoothGattDescriptor> descriptor = nullptr;
  for (uint32_t i = 0; i < mServices.Length(); i++) {
    for (uint32_t j = 0; j < mServices[i]->mCharacteristics.Length(); j++) {
      RefPtr<BluetoothGattCharacteristic> currentChar =
        mServices[i]->mCharacteristics[j];

      if (handle == currentChar->GetCharacteristicHandle()) {
        characteristic = currentChar;
        break;
      }

      size_t index = currentChar->mDescriptors.IndexOf(handle);
      if (index != currentChar->mDescriptors.NoIndex) {
        descriptor = currentChar->mDescriptors[index];
        break;
      }
    }
  }

  if (!(characteristic || descriptor)) {
    BT_WARNING("Wrong handle: no matched characteristic or descriptor");
    return;
  }

  // Save the request information for sending the response later
  RequestData data(handle,
                   characteristic,
                   descriptor);
  mRequestMap.Put(requestId, &data);

  RefPtr<BluetoothGattAttributeEvent> event =
    BluetoothGattAttributeEvent::Constructor(
      this, aEventName, address, requestId, characteristic, descriptor,
      &value, needResponse, false /* Bubble */, false /* Cancelable*/);

  DispatchTrustedEvent(event);
}
void
BluetoothAdapter::Notify(const BluetoothSignal& aData)
{
  InfallibleTArray<BluetoothNamedValue> arr;

  BT_LOGD("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());

  BluetoothValue v = aData.value();
  if (aData.name().EqualsLiteral("DeviceFound")) {
    nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value());
    nsCOMPtr<nsIDOMEvent> event;
    NS_NewDOMBluetoothDeviceEvent(getter_AddRefs(event), this, nullptr, nullptr);

    nsCOMPtr<nsIDOMBluetoothDeviceEvent> e = do_QueryInterface(event);
    e->InitBluetoothDeviceEvent(NS_LITERAL_STRING("devicefound"),
                                false, false, device);
    DispatchTrustedEvent(event);
  } else if (aData.name().EqualsLiteral("PropertyChanged")) {
    MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
    const InfallibleTArray<BluetoothNamedValue>& arr =
      v.get_ArrayOfBluetoothNamedValue();

    MOZ_ASSERT(arr.Length() == 1);
    SetPropertyByValue(arr[0]);
  } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) ||
             aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) ||
             aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) ||
             aData.name().EqualsLiteral(A2DP_STATUS_CHANGED_ID)) {
    MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
    const InfallibleTArray<BluetoothNamedValue>& arr =
      v.get_ArrayOfBluetoothNamedValue();

    MOZ_ASSERT(arr.Length() == 2 &&
               arr[0].value().type() == BluetoothValue::TnsString &&
               arr[1].value().type() == BluetoothValue::Tbool);
    nsString address = arr[0].value().get_nsString();
    bool status = arr[1].value().get_bool();

    nsCOMPtr<nsIDOMEvent> event;
    NS_NewDOMBluetoothStatusChangedEvent(
      getter_AddRefs(event), this, nullptr, nullptr);

    nsCOMPtr<nsIDOMBluetoothStatusChangedEvent> e = do_QueryInterface(event);
    e->InitBluetoothStatusChangedEvent(aData.name(), false, false,
                                       address, status);
    DispatchTrustedEvent(event);
  } else if (aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) {
    nsCOMPtr<nsIDOMEvent> event;
    nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
    NS_ENSURE_SUCCESS_VOID(rv);

    rv = event->InitEvent(aData.name(), false, false);
    NS_ENSURE_SUCCESS_VOID(rv);

    DispatchTrustedEvent(event);
  } else {
#ifdef DEBUG
    nsCString warningMsg;
    warningMsg.AssignLiteral("Not handling adapter signal: ");
    warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
    BT_WARNING(warningMsg.get());
#endif
  }
}
void
BluetoothAdapter::Notify(const BluetoothSignal& aData)
{
  InfallibleTArray<BluetoothNamedValue> arr;

  BT_LOGD("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());

  BluetoothValue v = aData.value();
  if (aData.name().EqualsLiteral("DeviceFound")) {
    nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value());

    BluetoothDeviceEventInit init;
    init.mBubbles = false;
    init.mCancelable = false;
    init.mDevice = device;
    nsRefPtr<BluetoothDeviceEvent> event =
      BluetoothDeviceEvent::Constructor(this, NS_LITERAL_STRING("devicefound"), init);
    DispatchTrustedEvent(event);
  } else if (aData.name().EqualsLiteral("PropertyChanged")) {
    MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);

    const InfallibleTArray<BluetoothNamedValue>& arr =
      v.get_ArrayOfBluetoothNamedValue();

    for (uint32_t i = 0, propCount = arr.Length(); i < propCount; ++i) {
      SetPropertyByValue(arr[i]);
    }
  } else if (aData.name().EqualsLiteral(DISCOVERY_STATE_CHANGED_ID)) {
    MOZ_ASSERT(v.type() == BluetoothValue::Tbool);

    BluetoothDiscoveryStateChangedEventInit init;
    init.mDiscovering = v.get_bool();

    nsRefPtr<BluetoothDiscoveryStateChangedEvent> event =
      BluetoothDiscoveryStateChangedEvent::Constructor(
        this, NS_LITERAL_STRING(DISCOVERY_STATE_CHANGED_ID), init);
    DispatchTrustedEvent(event);
  } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) ||
             aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) ||
             aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) ||
             aData.name().EqualsLiteral(A2DP_STATUS_CHANGED_ID)) {
    MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
    const InfallibleTArray<BluetoothNamedValue>& arr =
      v.get_ArrayOfBluetoothNamedValue();

    MOZ_ASSERT(arr.Length() == 2 &&
               arr[0].value().type() == BluetoothValue::TnsString &&
               arr[1].value().type() == BluetoothValue::Tbool);
    nsString address = arr[0].value().get_nsString();
    bool status = arr[1].value().get_bool();

    BluetoothStatusChangedEventInit init;
    init.mBubbles = false;
    init.mCancelable = false;
    init.mAddress = address;
    init.mStatus = status;
    nsRefPtr<BluetoothStatusChangedEvent> event =
      BluetoothStatusChangedEvent::Constructor(this, aData.name(), init);
    DispatchTrustedEvent(event);
  } else if (aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) {
    nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);

    nsresult rv = event->InitEvent(aData.name(), false, false);
    NS_ENSURE_SUCCESS_VOID(rv);

    DispatchTrustedEvent(event);
  } else {
#ifdef DEBUG
    nsCString warningMsg;
    warningMsg.AssignLiteral("Not handling adapter signal: ");
    warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
    BT_WARNING(warningMsg.get());
#endif
  }
}