play-billing 0.2.3

Google Play Billing Plugin for Crossbow
Documentation
use crossbow_android::{error::*, jni::JavaVM, plugin::*};
use std::sync::Arc;

pub struct PlayBillingPlugin {
    singleton: Arc<JniSingleton>,
    vm: Arc<JavaVM>,
}

impl CrossbowPlugin for PlayBillingPlugin {
    fn from_java_vm(vm: Arc<JavaVM>) -> Result<Self>
    where
        Self: Sized,
    {
        let singleton = get_jni_singleton(Self::get_plugin_name()).ok_or_else(|| {
            AndroidError::SingletonNotRegistered(Self::get_plugin_name().to_owned())
        })?;
        Ok(Self { singleton, vm })
    }

    fn get_plugin_name() -> &'static str {
        "CrossbowPlayBilling"
    }

    fn get_receiver(&self) -> &Receiver<Signal> {
        self.singleton.get_receiver()
    }
}

impl PlayBillingPlugin {
    pub fn start_connection(&self) -> Result<()> {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        self.singleton
            .call_method(&jnienv, "startConnection", &[])?;
        jnienv.exception_check()?;
        Ok(())
    }

    pub fn end_connection(&self) -> Result<()> {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        self.singleton.call_method(&jnienv, "endConnection", &[])?;
        jnienv.exception_check()?;
        Ok(())
    }

    pub fn is_ready(&self) -> Result<bool> {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let res = self.singleton.call_method(&jnienv, "isReady", &[])?;
        jnienv.exception_check()?;
        Ok(res.z()?)
    }

    pub fn get_connection_state(&self) -> Result<i32> {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let res = self
            .singleton
            .call_method(&jnienv, "getConnectionState", &[])?;
        jnienv.exception_check()?;
        Ok(res.i()?)
    }

    pub fn query_purchases<S>(&self, purchase_type: S) -> Result<()>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let purchase_type_str = jnienv.new_string(purchase_type)?;
        self.singleton
            .call_method(&jnienv, "queryPurchases", &[purchase_type_str.into()])?;
        jnienv.exception_check()?;
        Ok(())
    }

    pub fn query_sku_details<S>(&self, sku_list: &[S], sku_type: S) -> Result<()>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let empty_str = jnienv.new_string("")?;
        let string_array =
            jnienv.new_object_array(sku_list.len() as i32, "java/lang/String", empty_str)?;
        for (index, id) in sku_list.iter().enumerate() {
            let id_str = jnienv.new_string(id)?;
            jnienv.set_object_array_element(string_array, index as i32, id_str)?;
        }
        let sku_type_str = jnienv.new_string(sku_type)?;
        self.singleton.call_method(
            &jnienv,
            "querySkuDetails",
            &[string_array.into(), sku_type_str.into()],
        )?;
        jnienv.exception_check()?;
        Ok(())
    }

    pub fn acknowledge_purchase<S>(&self, purchase_token: S) -> Result<()>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let purchase_token_str = jnienv.new_string(purchase_token)?;
        self.singleton
            .call_method(&jnienv, "acknowledgePurchase", &[purchase_token_str.into()])?;
        jnienv.exception_check()?;
        Ok(())
    }

    pub fn consume_purchase<S>(&self, purchase_token: S) -> Result<()>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let purchase_token_str = jnienv.new_string(purchase_token)?;
        self.singleton
            .call_method(&jnienv, "consumePurchase", &[purchase_token_str.into()])?;
        jnienv.exception_check()?;
        Ok(())
    }

    pub fn confirm_price_change<S>(&self, sku: S) -> Result<JniRustType>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let sku_str = jnienv.new_string(sku)?;
        let res = self
            .singleton
            .call_method(&jnienv, "confirmPriceChange", &[sku_str.into()])?;
        jnienv.exception_check()?;
        Ok(JniRustType::from_jobject(&jnienv, res.l()?)?)
    }

    pub fn purchase<S>(&self, sku: S) -> Result<JniRustType>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let sku_str = jnienv.new_string(sku)?;
        let res = self
            .singleton
            .call_method(&jnienv, "purchase", &[sku_str.into()])?;
        jnienv.exception_check()?;
        Ok(JniRustType::from_jobject(&jnienv, res.l()?)?)
    }

    pub fn update_subscription<S>(
        &self,
        old_token: S,
        sku: S,
        proration_mode: i32,
    ) -> Result<JniRustType>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let old_token_str = jnienv.new_string(old_token)?;
        let sku_str = jnienv.new_string(sku)?;
        let res = self.singleton.call_method(
            &jnienv,
            "updateSubscription",
            &[old_token_str.into(), sku_str.into(), proration_mode.into()],
        )?;
        jnienv.exception_check()?;
        Ok(JniRustType::from_jobject(&jnienv, res.l()?)?)
    }

    pub fn set_obfuscated_account_id<S>(&self, account_id: S) -> Result<()>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let account_id_str = jnienv.new_string(account_id)?;
        self.singleton
            .call_method(&jnienv, "setObfuscatedAccountId", &[account_id_str.into()])?;
        jnienv.exception_check()?;
        Ok(())
    }

    pub fn set_obfuscated_profile_id<S>(&self, profile_id: S) -> Result<()>
    where
        S: AsRef<str>,
    {
        let jnienv = self.vm.attach_current_thread_as_daemon()?;
        let profile_id_str = jnienv.new_string(profile_id)?;
        self.singleton
            .call_method(&jnienv, "setObfuscatedProfileId", &[profile_id_str.into()])?;
        jnienv.exception_check()?;
        Ok(())
    }
}