/*
* Copyright 2014 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.checkout;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.GuardedBy;
/**
* Default Billing v.3 {@link Inventory}. Loads the purchase information from the {@link Checkout}.
*/
final class CheckoutInventory extends BaseInventory {
private class Worker implements Checkout.Listener, Runnable {
@Nonnull
private final Task mTask;
@GuardedBy("mLock")
private int mCount;
@GuardedBy("mLock")
private final Products mProducts = new Products();
public Worker(@Nonnull Task task) {
mTask = task;
}
@Override
public void run() {
// for each product we wait for:
// 1. onReady to be called
// 2. loadPurchased to be finished
// 3. loadSkus to be finished
mCount = ProductTypes.ALL.size() * 3;
mCheckout.whenReady(this);
}
@Override
public void onReady(@Nonnull BillingRequests requests) {
}
@Override
public void onReady(@Nonnull BillingRequests requests, @Nonnull String productId,
boolean billingSupported) {
final Product product = new Product(productId, billingSupported);
synchronized (mLock) {
countDown();
mProducts.add(product);
if (!mTask.isCancelled() && product.supported && mTask.getRequest().shouldLoadPurchases(productId)) {
loadPurchases(requests, product);
} else {
countDown(1);
}
if (!mTask.isCancelled() && product.supported && mTask.getRequest().shouldLoadSkus(productId)) {
loadSkus(requests, product);
} else {
countDown(1);
}
}
}
private void countDown() {
Check.isTrue(Thread.holdsLock(mLock), "Must be synchronized");
countDown(1);
}
private void countDown(int count) {
Check.isTrue(Thread.holdsLock(mLock), "Must be synchronized");
mCount -= count;
Check.isTrue(mCount >= 0, "Can't be negative");
if (mCount == 0) {
mTask.onDone(mProducts);
}
}
private void loadPurchases(@Nonnull final BillingRequests requests,
@Nonnull final Product product) {
requests.getAllPurchases(product.id, synchronizedListener(new RequestListener<Purchases>() {
@Override
public void onSuccess(@Nonnull Purchases purchases) {
product.setPurchases(purchases.list);
countDown();
}
@Override
public void onError(int response, @Nonnull Exception e) {
countDown();
}
}));
}
private void loadSkus(@Nonnull BillingRequests requests, @Nonnull final Product product) {
final List<String> skuIds = mTask.getRequest().getSkus(product.id);
if (skuIds.isEmpty()) {
Billing.warning("There are no SKUs for \"" + product.id
+ "\" product. No SKU information will be loaded");
synchronized (mLock) {
countDown();
}
return;
}
requests.getSkus(product.id, skuIds, synchronizedListener(new RequestListener<Skus>() {
@Override
public void onSuccess(@Nonnull Skus skus) {
product.setSkus(skus.list);
countDown();
}
@Override
public void onError(int response, @Nonnull Exception e) {
countDown();
}
}));
}
}
CheckoutInventory(@Nonnull Checkout checkout) {
super(checkout);
}
@Nonnull
@Override
protected Runnable createWorker(Task task) {
return new Worker(task);
}
}