crossbow_android/plugin/
jni_singleton.rs1use super::JniRustType;
2use async_channel::Receiver;
3use jni::{
4 errors::*,
5 objects::{GlobalRef, JClass, JObject, JValue},
6 signature::{JavaType, TypeSignature},
7 JNIEnv,
8};
9use std::collections::HashMap;
10
11#[derive(Clone)]
12pub struct JniSingleton {
13 name: String,
14 instance: GlobalRef,
15 methods: HashMap<String, JniSingletonMethod>,
16 signals: HashMap<String, Vec<JavaType>>,
17 receiver: Receiver<Signal>,
18}
19
20#[derive(Clone, Debug)]
21pub struct Signal {
22 pub name: String,
23 pub args: Vec<JniRustType>,
24}
25
26#[derive(Clone)]
27pub struct JniSingletonMethod {
28 class: GlobalRef,
29 signature: TypeSignature,
30}
31
32impl JniSingleton {
33 pub fn new(name: &str, instance: GlobalRef, receiver: Receiver<Signal>) -> Self {
34 Self {
35 name: name.to_string(),
36 instance,
37 methods: HashMap::new(),
38 signals: HashMap::new(),
39 receiver,
40 }
41 }
42
43 pub fn get_instance(&self) -> JObject {
44 self.instance.as_obj()
45 }
46
47 pub fn get_name(&self) -> &str {
48 &self.name
49 }
50
51 pub fn get_receiver(&self) -> &Receiver<Signal> {
52 &self.receiver
53 }
54
55 pub fn get_method(&self, name: &str) -> Option<&JniSingletonMethod> {
56 self.methods.get(name)
57 }
58
59 pub fn get_methods(&self) -> &HashMap<String, JniSingletonMethod> {
60 &self.methods
61 }
62
63 pub(crate) fn add_method(&mut self, name: &str, class: GlobalRef, signature: TypeSignature) {
64 self.methods
65 .insert(name.to_owned(), JniSingletonMethod { class, signature });
66 }
67
68 pub(crate) fn add_signal_info(&mut self, name: &str, args: Vec<JavaType>) {
69 self.signals.insert(name.to_owned(), args);
70 }
71
72 pub fn call_method<'a>(
73 &'a self,
74 env: &'a JNIEnv,
75 name: &str,
76 args: &[JValue],
77 ) -> Result<JValue<'a>> {
78 let method = match self.get_method(name) {
79 Some(method) => method,
80 None => Err(Error::MethodNotFound {
81 name: name.to_owned(),
82 sig: "".to_owned(),
83 })?,
84 };
85 let class: JClass = method.class.as_obj().into();
86 let method_id = env.get_method_id(class, name, method.signature.to_string())?;
87
88 let result = env.call_method_unchecked(
89 self.get_instance(),
90 method_id,
91 method.signature.ret.clone(),
92 args,
93 )?;
94 env.exception_check()?;
95 Ok(result)
96 }
97}