/* * AndFHEM - Open Source Android application to control a FHEM home automation * server. * * Copyright (c) 2011, Matthias Klass or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GENERAL PUBLIC LICENSE * for more details. * * You should have received a copy of the GNU GENERAL PUBLIC LICENSE * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package li.klass.fhem.billing; import android.app.Activity; import android.content.Context; import com.android.vending.billing.IabHelper; import com.android.vending.billing.IabResult; import com.android.vending.billing.Inventory; import com.android.vending.billing.Purchase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Singleton; import static com.google.common.base.Preconditions.checkNotNull; import static li.klass.fhem.AndFHEMApplication.PUBLIC_KEY_ENCODED; @Singleton public class BillingService { private IabHelper iabHelper = null; private Inventory inventory = Inventory.empty(); private static final Logger LOG = LoggerFactory.getLogger(BillingService.class); @Inject public BillingService() { } public synchronized void stop() { try { if (iabHelper != null) { iabHelper.dispose(); iabHelper = null; } } catch (Exception e) { LOG.debug("stop() - cannot stop", e); } } public synchronized void requestPurchase(final Activity activity, final String itemId, final String payload, final ProductPurchasedListener listener) { LOG.info("requestPurchase() - requesting purchase of " + itemId); ensureSetup(new SetupFinishedListener() { @Override public void onSetupFinished(boolean success) { try { if (!success) { LOG.error("requestPurchase() - cannot initialize purchase flow, setup was not successful"); } else { iabHelper.flagEndAsync(); iabHelper.launchPurchaseFlow(activity, itemId, 0, new IabHelper.OnIabPurchaseFinishedListener() { @Override public void onIabPurchaseFinished(IabResult result, Purchase info) { if (result.isSuccess()) { LOG.info("requestPurchase() - purchase result: SUCCESS"); loadInventory(activity); listener.onProductPurchased(info.getOrderId(), info.getSku()); } else { LOG.error("requestPurchase() - purchase result: " + result.toString()); } } }, payload); } } catch (Exception e) { LOG.error("requestPurchase() - error while launching purchase flow", e); } } }, activity); } private synchronized void loadInventory(Context context) { loadInventory(null, context); } public synchronized void loadInventory(final OnLoadInventoryFinishedListener listener, Context context) { if (isLoaded()) { LOG.debug("loadInventory() - inventory is already setup and loaded, skipping load (" + inventory + ")"); if (listener != null) listener.onInventoryLoadFinished(true); } else { ensureSetup(new SetupFinishedListener() { @Override public void onSetupFinished(boolean success) { if (success) { LOG.debug("loadInventory() - calling load internal"); loadInternal(listener); } else { LOG.debug("loadInventory() - won't load inventory, setup was not successful"); listener.onInventoryLoadFinished(false); } } }, context); } } public synchronized boolean contains(final String sku) { return inventory != null && inventory.hasPurchase(sku); } private boolean isSetup() { return iabHelper != null && iabHelper.isSetupDone(); } private boolean isLoaded() { return inventory != null && !inventory.getAllOwnedSkus().isEmpty(); } private void ensureSetup(SetupFinishedListener listener, Context context) { if (isSetup()) { LOG.debug("ensureSetup() - I am already setup"); listener.onSetupFinished(true); } else { String isSetupDoneMessage = iabHelper != null ? ",isSetupDone=" + iabHelper.isSetupDone() : ""; LOG.debug("ensureSetup() - Setting up ... (helper=" + iabHelper + isSetupDoneMessage + ")"); setup(listener, context); } } synchronized void setup(final SetupFinishedListener listener, Context context) { checkNotNull(listener); try { LOG.debug("setup() - Starting setup " + this); iabHelper = createIabHelper(context); iabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { @Override public void onIabSetupFinished(IabResult result) { checkNotNull(iabHelper, "setup() - iabHelper may not be null after setup"); try { if (result.isSuccess()) { LOG.debug("setup() : setup was successful, setupIsDone=" + iabHelper.isSetupDone()); } else { LOG.error("setup() : ERROR " + result.toString()); } listener.onSetupFinished(true); } catch (Exception e) { inventory = Inventory.empty(); LOG.error("setup() : error during setup", e); listener.onSetupFinished(false); } } }); } catch (Exception e) { LOG.info("setup() - Error while trying to start billing", e); listener.onSetupFinished(false); } } IabHelper createIabHelper(Context context) { return new IabHelper(context, PUBLIC_KEY_ENCODED); } private synchronized void loadInternal(final OnLoadInventoryFinishedListener listener) { checkNotNull(iabHelper); boolean success = false; try { if (isLoaded()) { LOG.debug("loadInternal() - inventory was already loaded, skipping load"); } else if (!iabHelper.isSetupDone()) { inventory = Inventory.empty(); LOG.error("loadInternal() - setup was not done, initializing with empty inventory"); } else { LOG.debug("loadInternal() - loading inventory"); inventory = iabHelper.queryInventory(false, null); LOG.debug("loadInternal() - query inventory finished, inventory is " + inventory); } success = true; } catch (Exception e) { LOG.error("loadInternal() - cannot load inventory", e); } finally { if (inventory == null) { LOG.error("loadInternal() - inventory was null, setting it to an empty inventory"); inventory = Inventory.empty(); } if (listener != null) { listener.onInventoryLoadFinished(success); } } } IabHelper getIabHelper() { return iabHelper; } Inventory getInventory() { return inventory; } void setIabHelper(IabHelper iabHelper) { this.iabHelper = iabHelper; } public interface ProductPurchasedListener { void onProductPurchased(String orderId, String productId); } public interface OnLoadInventoryFinishedListener { void onInventoryLoadFinished(boolean success); } public interface SetupFinishedListener { void onSetupFinished(boolean success); } }