XMPP only has to turn the radio on full power mode when it gets a new message or creates a new connection (the tower sends the LTE radio a paging message telling it to wake up, then the long-lived TCP connection can receive data). Matrix has to turn the radio on every single time it wants to check for data, regardless of whether there is data to receive or not. This is the problem with HTTP based protocols; you might have a persistent TCP connection, but it doesn't help you when you have to send a request just to check if there are new messages.
It's not a case of radio off vs on, it's a case of the radio being able to stay in RRC_IDLE mode (which I've probably called "off" more than once, which is where the confusion came from I'm sure, apologies for that) for more of the time, where as with Matrix it almost always has to remain RRC_CONNECTED mode.
I don't believe this is true. The long-polling that Matrix does in the baseline impl is just a long-lived HTTP request which blocks until the server has something to send it. Radio-wise this is conceptually the same as an XMPP TCP connection.
The only difference is that (in the baseline impl) you start a new HTTP request after receiving each response - which chews some additional data relative to XMPP. The radio will already be spun up from receiving the previous data, though, so it shouldn't impact significantly on battery consumption.
Also, we put a timeout on the long-lived request (typically 30-60s), to aid recovery in case of the request or connectivity breaking - which could theoretically increase bandwidth and radio battery consumption, but in practice almost all Matrix use cases involve receiving events more frequently than the timeout, so the timeout doesn't actually have much impact on battery.
That said, there is (deliberately) huge scope for improvement with alternative transports - using strict push rather than long-polling; using transports with less overhead; using more efficient encodings, etc.
It's not a case of radio off vs on, it's a case of the radio being able to stay in RRC_IDLE mode (which I've probably called "off" more than once, which is where the confusion came from I'm sure, apologies for that) for more of the time, where as with Matrix it almost always has to remain RRC_CONNECTED mode.