I read that we use call() only when we don't know the ABI of the called contract and we don't know its source code
This isnt true and i wonder when you read that. As you already figured out, to call a function with .call, you need to know its name (or its selector, at least, which you can figure out from a disassembly, if you really don't have access to the source code) and the arguments it takes (if any). .call is mostly used in the case mentionned by Gonzalo's answer (to send Ether when you arent certain the recipient is an EOA, because the otherwise recommended .transfer() doesnt forward enough gas to allow a contract to do anything), but there is a few others, such as being able to keep the transaction going after the call reverts
function callX(address x) {
// If the call to x reverts, 'success' will be set to false instead of the whole transaction reverting.
(bool success, bytes memory data) = x.call("");
if(success) {
doSomething();
}
else {
doSomethingElse();
}
}
Another one i can think of off the top of my head is when you don't know exactly how the called function is going to behave (Uniswap's safeTransfer is a good example of that, read my answer on Why does Uniswap V2 use `_safeTransfer` to transfer tokens? for more explanations)