All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mle.android.iap.amazon.AsyncAmazonIapHelper.scala Maven / Gradle / Ivy

The newest version!
package com.mle.android.iap.amazon

import android.content.Context
import com.amazon.inapp.purchasing.ItemDataResponse.ItemDataRequestStatus
import com.amazon.inapp.purchasing._
import com.mle.android.iap._
import com.mle.concurrent.ExecutionContexts.cached
import com.mle.concurrent.PromiseHelpers

import scala.concurrent.Promise

/**
 * This class registers itself as the observer for the [[com.amazon.inapp.purchasing.PurchasingManager]] upon
 * construction.
 *
 * Clients shall not use this class directly. Instead, use [[com.mle.android.iap.amazon.AmazonIapUtils]].
 *
 * TODO: Create rx observables that get new values when the callbacks are called. Futures are one-off and a bad match
 * for this API.
 *
 * @author mle
 */
class AsyncAmazonIapHelper(ctx: Context) extends AmazonPurchasingObserver(ctx) with PromiseHelpers {
  private val isSandboxAllowed: Boolean = true
  private val purchaseUpdateFailureMessage = "Unable to read purchase status."
  private val itemStatusFailureMessage = "Unable to read item data."
  private val getUserFailureMessage = "Unable to read the current user ID."

  private val isSandboxPromise = Promise[Boolean]()
  private val userIdPromise = Promise[String]()
  private val entitledPromise = Promise[Set[String]]()
  private val revokedPromise = Promise[Set[String]]()
  private val purchasePromise = Promise[String]()
  private val availableItemsPromise = Promise[Set[ProductInfo]]()

  val isSandbox = isSandboxPromise.future
  val entitledSkus = entitledPromise.future
  val revokedSkus = revokedPromise.future
  val availableItems = availableItemsPromise.future
  val userId = userIdPromise.future
  val purchase = purchasePromise.future

  // I think there's at most one observer at any given time and the last one registered wins
  PurchasingManager.registerObserver(this)

  def hasSku(sku: String) = entitledSkus.map(_.contains(sku))

  def onEntitledSkus(skus: Set[String]): Unit = trySuccess(skus, entitledPromise)

  def onRevokedSkus(skus: Set[String]): Unit = trySuccess(skus, revokedPromise)

  override def onSdkAvailable(isSandboxMode: Boolean): Unit = {
    super.onSdkAvailable(isSandboxMode)
    trySuccess(isSandboxMode, isSandboxPromise)
    if (isSandboxMode && !isSandboxAllowed) {
      tryFailure(new SandboxModeException, userIdPromise)
    }
    if (!isSandboxMode || isSandboxAllowed) {
      // the getUserId callback calls the get purchase status,
      // the callback of which will eventually complete the promises
      PurchasingManager.initiateGetUserIdRequest()
    }
  }

  def onUserId(userId: String) = {
    //    info(s"Amazon IAP user identified as: $userId")
    trySuccess(userId, userIdPromise)
  }

  override def onGetUserIdFailed(response: GetUserIdResponse): Unit = {
    super.onGetUserIdFailed(response)
    val ex = new IapException(getUserFailureMessage)
    tryFailure(ex, userIdPromise, entitledPromise, revokedPromise)
  }

  override def onPurchaseStatusFailed(response: PurchaseUpdatesResponse): Unit = {
    super.onPurchaseStatusFailed(response)
    val ex = new IapException(purchaseUpdateFailureMessage)
    tryFailure(ex, entitledPromise, revokedPromise)
  }


  override def onItemDataResponse(response: ItemDataResponse): Unit = {
    super.onItemDataResponse(response)
    if (response.getItemDataRequestStatus == ItemDataRequestStatus.SUCCESSFUL) {
      import scala.collection.JavaConversions._
      val infos = response.getItemData.values()
        .map(item => ProductInfo(item.getSku, item.getPrice, item.getTitle, item.getDescription)).toSet
      trySuccess(infos, availableItemsPromise)
    } else {
      val ex = new IapException(itemStatusFailureMessage)
      tryFailure(ex, availableItemsPromise)
    }
  }

  def onPurchaseSucceeded(sku: String): Unit = trySuccess(sku, purchasePromise)

  def onPurchaseFailed(response: PurchaseResponse): Unit = {
    import com.amazon.inapp.purchasing.PurchaseResponse.PurchaseRequestStatus._
    val ex = response.getPurchaseRequestStatus match {
      case INVALID_SKU => new AmazonInvalidSkuException(response)
      case ALREADY_ENTITLED => new AmazonAlreadyPurchasedException(response)
      case _ => new AmazonPurchaseException(IapUtilsBase.purchaseFailedMessage, response)
    }
    tryFailure(ex, purchasePromise)
  }
}

class AmazonPurchaseException(msg: String, val response: PurchaseResponse) extends IapException(msg)

class AmazonInvalidSkuException(val response: PurchaseResponse) extends InvalidSkuException

class AmazonAlreadyPurchasedException(response: PurchaseResponse) extends AlreadyPurchasedException

class SandboxModeException extends IapException("The purchasing manager is running in sandbox mode. Please ensure that you have downloaded this app from Amazon AppStore, then try again.")




© 2015 - 2025 Weber Informatics LLC | Privacy Policy