use protobuf::Message;
use crate::{
AndroidAutoConfiguration, AndroidAutoFrame, AndroidAutoMainTrait, ChannelHandlerTrait,
ChannelId, FrameHeader, FrameHeaderType, StreamMux, Wifi, common::AndroidAutoCommonMessage,
frame_header::FrameHeaderContents,
};
#[derive(Debug)]
enum InputMessage {
BindingRequest(ChannelId, Wifi::BindingRequest),
BindingResponse(ChannelId, Wifi::BindingResponse),
InputEvent(ChannelId, Wifi::InputEventIndication),
}
impl From<InputMessage> for AndroidAutoFrame {
fn from(value: InputMessage) -> Self {
match value {
InputMessage::BindingRequest(_, _) => unimplemented!(),
InputMessage::BindingResponse(chan, m) => {
let mut data = m.write_to_bytes().unwrap();
let t = Wifi::input_channel_message::Enum::BINDING_RESPONSE as u16;
let t = t.to_be_bytes();
let mut m = Vec::new();
m.push(t[0]);
m.push(t[1]);
m.append(&mut data);
AndroidAutoFrame {
header: FrameHeader {
channel_id: chan,
frame: FrameHeaderContents::new(true, FrameHeaderType::Single, false),
},
data: m,
}
}
InputMessage::InputEvent(chan, m) => {
let mut data = m.write_to_bytes().unwrap();
let t = Wifi::input_channel_message::Enum::INPUT_EVENT_INDICATION as u16;
let t = t.to_be_bytes();
let mut m = Vec::new();
m.push(t[0]);
m.push(t[1]);
m.append(&mut data);
AndroidAutoFrame {
header: FrameHeader {
channel_id: chan,
frame: FrameHeaderContents::new(true, FrameHeaderType::Single, false),
},
data: m,
}
}
}
}
}
impl TryFrom<&AndroidAutoFrame> for InputMessage {
type Error = String;
fn try_from(value: &AndroidAutoFrame) -> Result<Self, Self::Error> {
use protobuf::Enum;
let mut ty = [0u8; 2];
ty.copy_from_slice(&value.data[0..2]);
let ty = u16::from_be_bytes(ty);
if let Some(sys) = Wifi::input_channel_message::Enum::from_i32(ty as i32) {
match sys {
Wifi::input_channel_message::Enum::BINDING_REQUEST => {
let m = Wifi::BindingRequest::parse_from_bytes(&value.data[2..]);
match m {
Ok(m) => Ok(Self::BindingRequest(value.header.channel_id, m)),
Err(e) => Err(format!("Invalid input bind request: {}", e)),
}
}
Wifi::input_channel_message::Enum::BINDING_RESPONSE => unimplemented!(),
Wifi::input_channel_message::Enum::INPUT_EVENT_INDICATION => todo!(),
Wifi::input_channel_message::Enum::NONE => todo!(),
}
} else {
Err(format!("Not converted message: {:x?}", value.data))
}
}
}
pub struct InputChannelHandler {}
impl ChannelHandlerTrait for InputChannelHandler {
fn build_channel<T: AndroidAutoMainTrait + ?Sized>(
&self,
_config: &AndroidAutoConfiguration,
chanid: ChannelId,
main: &T,
) -> Option<Wifi::ChannelDescriptor> {
let mut chan = Wifi::ChannelDescriptor::new();
chan.set_channel_id(chanid as u32);
let mut ichan = Wifi::InputChannel::new();
let ics = main.retrieve_input_configuration();
if let Some((w, h)) = ics.touchscreen {
let mut tc = Wifi::TouchConfig::new();
tc.set_height(h as u32);
tc.set_width(w as u32);
ichan.touch_screen_config.0.replace(Box::new(tc));
}
for c in &ics.keycodes {
log::error!("Keycode {} added", c);
ichan.supported_keycodes.push(*c);
}
chan.input_channel.0.replace(Box::new(ichan));
if !chan.is_initialized() {
panic!("Channel not initialized?");
}
Some(chan)
}
async fn receive_data<T: AndroidAutoMainTrait + ?Sized>(
&self,
msg: AndroidAutoFrame,
stream: &crate::WriteHalf,
_config: &AndroidAutoConfiguration,
main: &T,
) -> Result<(), super::FrameIoError> {
let channel = msg.header.channel_id;
let msg2: Result<InputMessage, String> = (&msg).try_into();
if let Ok(msg2) = msg2 {
match msg2 {
InputMessage::BindingRequest(chan, m) => {
let mut status = true;
let ics = main.retrieve_input_configuration();
for c in &m.scan_codes {
if !ics.keycodes.contains(&(*c as u32)) {
status = false;
break;
}
if main.binding_request(*c as u32).await.is_err() {
status = false;
break;
}
}
let mut m2 = Wifi::BindingResponse::new();
m2.set_status(if status {
Wifi::status::Enum::OK
} else {
Wifi::status::Enum::FAIL
});
stream
.write_frame(InputMessage::BindingResponse(chan, m2).into())
.await?;
}
InputMessage::BindingResponse(_, _) => unimplemented!(),
InputMessage::InputEvent(_, _) => unimplemented!(),
}
return Ok(());
}
let msg2: Result<AndroidAutoCommonMessage, String> = (&msg).try_into();
if let Ok(msg2) = msg2 {
match msg2 {
AndroidAutoCommonMessage::ChannelOpenResponse(_, _) => unimplemented!(),
AndroidAutoCommonMessage::ChannelOpenRequest(_m) => {
let mut m2 = Wifi::ChannelOpenResponse::new();
m2.set_status(Wifi::status::Enum::OK);
stream
.write_frame(
AndroidAutoCommonMessage::ChannelOpenResponse(channel, m2).into(),
)
.await?;
}
}
return Ok(());
}
todo!();
}
}