Android Open Source - gdx-pay Purchase Manager Android Amazon






From Project

Back to project page gdx-pay.

License

The source code is released under:

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUC...

If you think the Android project gdx-pay listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*******************************************************************************
 * Copyright 2011 See AUTHORS file./*from ww  w.j a v a 2  s .c om*/
 *
 * 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.
 ******************************************************************************/

package com.badlogic.gdx.pay.android.amazon;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.amazon.device.iap.PurchasingListener;
import com.amazon.device.iap.PurchasingService;
import com.amazon.device.iap.model.ProductDataResponse;
import com.amazon.device.iap.model.PurchaseResponse;
import com.amazon.device.iap.model.PurchaseUpdatesResponse;
import com.amazon.device.iap.model.Receipt;
import com.amazon.device.iap.model.UserData;
import com.amazon.device.iap.model.UserDataResponse;
import com.badlogic.gdx.pay.Information;
import com.badlogic.gdx.pay.PurchaseManager;
import com.badlogic.gdx.pay.PurchaseManagerConfig;
import com.badlogic.gdx.pay.PurchaseObserver;
import com.badlogic.gdx.pay.Transaction;

/** The purchase manager implementation for OUYA.
 * <p>
 * Include the gdx-pay-android-ouya.jar for this to work (plus gdx-pay-android.jar). Also update the "uses-permission" settings in
 * AndroidManifest.xml and your proguard settings.
 * 
 * @author just4phil */
public class PurchaseManagerAndroidAmazon implements PurchaseManager, PurchasingListener {

  /** Debug tag for logging. */
  private static final String TAG = "GdxPay/Amazon";
  private static final boolean LOGDEBUG     = true;
  private static final boolean SHOWTOASTS   = false;
  private static final int LOGTYPELOG = 0;
  private static final int LOGTYPEERROR = 1;

  /** Our Android activity. */
  Activity activity;

  /** The registered observer. */
  PurchaseObserver observer;

  /** The configuration. */
  PurchaseManagerConfig config;
  
  /** The productList */
  Set<String> productIdentifiers;
  
  // ------- for Toasts (debugging) -----
  String toastText;
  int duration;

  private String currentUserId = null;
  private String currentMarketplace = null;
  
  // --------------------------------------------------

  public PurchaseManagerAndroidAmazon (Activity activity, int requestCode) {
    this.activity = activity;
  }

  @Override
  public String storeName () {
    return PurchaseManagerConfig.STORE_NAME_ANDROID_AMAZON;
  }

  @Override
  public void install (final PurchaseObserver observer, PurchaseManagerConfig config) {
    this.observer = observer;
    this.config = config;
    
    // --- copy all available products to the list of productIdentifiers
    int offerSize = config.getOfferCount();
    productIdentifiers = new HashSet<String>(offerSize);
    for (int z = 0; z < config.getOfferCount(); z++) {
      productIdentifiers.add(config.getOffer(z).getIdentifierForStore(storeName()));
    }
    
    PurchasingService.registerListener(activity.getApplicationContext(), this);
    
    // PurchasingService.IS_SANDBOX_MODE returns a boolean value. 
    // Use this boolean value to check whether your app is running in test mode under the App Tester 
    // or in the live production environment.
    showMessage(LOGTYPELOG, "Amazon IAP: sandbox mode is:" + PurchasingService.IS_SANDBOX_MODE);
    
    observer.handleInstall();
    
    PurchasingService.getUserData();
  }

  // ----- Handler --------------------

  Handler handler = new HandlerExtension(Looper.getMainLooper());

  final static int showToast = 0;

  final class HandlerExtension extends Handler {

    public HandlerExtension(Looper mainLooper) {
      super(mainLooper);
    }

    @Override
    public void handleMessage (Message msg) {

      switch (msg.what) {

      case showToast:
        Toast toast = Toast.makeText(activity, toastText, duration);
        toast.show();
        break;
      }
    }
  }

  @Override
  public void purchase(String identifier) {  
    String identifierForStore = config.getOffer(identifier).getIdentifierForStore(storeName());
    String requestId = PurchasingService.purchase(identifierForStore).toString();    
  }

  @Override
  public void purchaseRestore() {
    PurchasingService.getPurchaseUpdates(true);    // true: always gets ALL purchased items (complete history)
  }
  
//=====================================================================================

      /**
       * Method to handle receipts
       * 
       * @param requestId
       * @param receipt
       * @param userData
       */
      public void handleReceipt(final String requestId, final Receipt receipt, final UserData userData) {
          
         // convert receipt to transaction
          Transaction trans = convertReceiptToTransaction(1, requestId, receipt, userData);  // provides cancleState also
          
        switch (receipt.getProductType()) {
                  
          case CONSUMABLE:
              // TODO: check consumable sample for how to handle consumable purchases
              break;
              
          case ENTITLED:
        // inform the listener
        observer.handlePurchase(trans);
              break;
              
          case SUBSCRIPTION:
              // TODO: check subscription sample for how to handle consumable purchases
              break;
          }
      }
//====================================================================================

//  public void onActivityResult (int requestCode, int resultCode, Intent data) {
//    // forwards activities to OpenIAB for processing
//    // this is only relevant for android
//  }

  void showMessage (final int type, final String message) {
    if (LOGDEBUG) {
      if (type == LOGTYPELOG) Log.d(TAG, message);
      if (type == LOGTYPEERROR) Log.e(TAG, message);
    }
    if (SHOWTOASTS) {
      if (type == LOGTYPELOG) showToast(message);
      if (type == LOGTYPEERROR) showToast("error: " + message);
    }
  }

  // ---- saves the toast text and displays it
  void showToast (String toastText) {
    this.duration = Toast.LENGTH_SHORT;
    this.toastText = toastText;
    handler.sendEmptyMessage(showToast);
  }

  @Override
  public boolean installed () {
//    if (PurchaseSystem.hasManager()) return true;  // this leads to unwanted binding via reflection !!
    return observer != null;
  }

  @Override
  public void dispose () {

    if (observer != null) {      
      // remove observer and config as well
      observer = null;
      config = null;
      showMessage(LOGTYPELOG, "disposed all the Amazon IAP stuff.");
    }
  }

    @Override
    public Information getInformation(String identifier) {
        // not implemented yet for this purchase manager -> TODO
        return Information.UNAVAILABLE;
    }
    
    
    //=================================================
    
    
  
    /**
     * This is the callback for {@link PurchasingService#getUserData}. For
     * successful case, get the current user from {@link UserDataResponse} and
     * call {@link SampleIAPManager#setAmazonUserId} method to load the Amazon
     * user and related purchase information
     * 
     * @param response
     */
    @Override
    public void onUserDataResponse(final UserDataResponse response) {
      showMessage(LOGTYPELOG,  "onGetUserDataResponse: requestId (" + response.getRequestId()
                   + ") userIdRequestStatus: "
                   + response.getRequestStatus()
                   + ")");

        final UserDataResponse.RequestStatus status = response.getRequestStatus();
        
        switch (status) {
        case SUCCESSFUL:
          showMessage(LOGTYPELOG,  "onUserDataResponse: get user id (" + response.getUserData().getUserId()
                       + ", marketplace ("
                       + response.getUserData().getMarketplace()
                       + ") ");
            currentUserId = response.getUserData().getUserId();
            currentMarketplace = response.getUserData().getMarketplace();
            break;

        case FAILED:
        case NOT_SUPPORTED:
          showMessage(LOGTYPEERROR,  "onUserDataResponse failed, status code is " + status);
            currentUserId = null;
            currentMarketplace = null;
            break;
        }
    }

    
    //========= TODO =============
    /**
     * This is the callback for {@link PurchasingService#getProductData}. After
     * SDK sends the product details and availability to this method, it will
     * call {@link SampleIAPManager#enablePurchaseForSkus}
     * {@link SampleIAPManager#disablePurchaseForSkus} or
     * {@link SampleIAPManager#disableAllPurchases} method to set the purchase
     * status accordingly.
     */
    @Override
    public void onProductDataResponse(final ProductDataResponse response) {
        final ProductDataResponse.RequestStatus status = response.getRequestStatus();
        showMessage(LOGTYPELOG,  "onProductDataResponse: RequestStatus (" + status + ")");

        switch (status) {
        case SUCCESSFUL:
          showMessage(LOGTYPELOG,  "onProductDataResponse: successful.  The item data map in this response includes the valid SKUs");
            final Set<String> unavailableSkus = response.getUnavailableSkus();
            showMessage(LOGTYPELOG,  "onProductDataResponse: " + unavailableSkus.size() + " unavailable skus");
//            enablePurchaseForSkus(response.getProductData());
//            disablePurchaseForSkus(response.getUnavailableSkus());
//            refreshLevel2Availability();
            break;
            
        case FAILED:
        case NOT_SUPPORTED:
          showMessage(LOGTYPEERROR,  "onProductDataResponse: failed, should retry request");
//            disableAllPurchases();
            break;
        }
    }

    /**
     * This is the callback for {@link PurchasingService#getPurchaseUpdates}.
     * 
     * You will receive Entitlement receipts from this callback.
     * 
     */
    @Override
    public void onPurchaseUpdatesResponse(final PurchaseUpdatesResponse response) {
      showMessage(LOGTYPELOG,  "onPurchaseUpdatesResponse: requestId (" + response.getRequestId()
                   + ") purchaseUpdatesResponseStatus ("
                   + response.getRequestStatus()
                   + ") userId ("
                   + response.getUserData().getUserId()
                   + ")");
        final PurchaseUpdatesResponse.RequestStatus status = response.getRequestStatus();
        switch (status) {
        case SUCCESSFUL:

            currentUserId = response.getUserData().getUserId();
            currentMarketplace = response.getUserData().getMarketplace();
            
//            for (final Receipt receipt : response.getReceipts()) {
//                handleReceipt(response.getRequestId().toString(), receipt, response.getUserData());
//            }

            // send result to observer --------
      List<Transaction> transactions = new ArrayList<Transaction>(response.getReceipts().size());

      for (int i = 0; i < response.getReceipts().size(); i++) {
        transactions.add(convertReceiptToTransaction(i, response.getRequestId().toString(), response.getReceipts().get(i), response.getUserData()));
      }
      // send inventory to observer
      observer.handleRestore(transactions.toArray(new Transaction[transactions.size()]));
      
      //---- check if there are more receipts -------
            if (response.hasMore()) {
                PurchasingService.getPurchaseUpdates(false);
            }
            break;
            
        case FAILED:
          showMessage(LOGTYPEERROR,  "onPurchaseUpdatesResponse: FAILED, should retry request");
//          disableAllPurchases();
          observer.handleRestoreError(new Throwable("onPurchaseUpdatesResponse: FAILED, should retry request"));
          break;
          
        case NOT_SUPPORTED:
          showMessage(LOGTYPEERROR,  "onPurchaseUpdatesResponse: NOT_SUPPORTED, should retry request");
//            disableAllPurchases();
          observer.handleRestoreError(new Throwable("onPurchaseUpdatesResponse: NOT_SUPPORTED, should retry request"));
            break;
        }

    }

    /**
     * This is the callback for {@link PurchasingService#purchase}. For each
     * time the application sends a purchase request
     * {@link PurchasingService#purchase}, Amazon Appstore will call this
     * callback when the purchase request is completed. If the RequestStatus is
     * Successful or AlreadyPurchased then application needs to call
     * {@link SampleIAPManager#handleReceipt} to handle the purchase
     * fulfillment. If the RequestStatus is INVALID_SKU, NOT_SUPPORTED, or
     * FAILED, notify corresponding method of {@link SampleIAPManager} .
     */
    @Override
    public void onPurchaseResponse(final PurchaseResponse response) {
        final String requestId = response.getRequestId().toString();
        final String userId = response.getUserData().getUserId();
        final PurchaseResponse.RequestStatus status = response.getRequestStatus();
        showMessage(LOGTYPELOG,  "onPurchaseResponse: requestId (" + requestId
                   + ") userId ("
                   + userId
                   + ") purchaseRequestStatus ("
                   + status
                   + ")");

        switch (status) {
        case SUCCESSFUL:
            final Receipt receipt = response.getReceipt();
            
            currentUserId = userId;
            currentMarketplace = response.getUserData().getMarketplace();
            showMessage(LOGTYPELOG,  "onPurchaseResponse: receipt json:" + receipt.toJSON());
            handleReceipt(response.getRequestId().toString(), receipt, response.getUserData());
            break;
            
        case ALREADY_PURCHASED:
          showMessage(LOGTYPELOG, "onPurchaseResponse: already purchased, you should verify the entitlement purchase on your side and make sure the purchase was granted to customer");
          observer.handlePurchaseError(new Throwable("onPurchaseResponse: ALREADY_PURCHASED"));
            break;
            
        case INVALID_SKU:
          showMessage(LOGTYPEERROR, 
                  "onPurchaseResponse: invalid SKU!  onProductDataResponse should have disabled buy button already.");
//            final Set<String> unavailableSkus = new HashSet<String>();
//            unavailableSkus.add(response.getReceipt().getSku());
//            disablePurchaseForSkus(unavailableSkus);
          observer.handlePurchaseError(new Throwable("onPurchaseResponse: INVALID_SKU"));
            break;
            
        case FAILED:
          showMessage(LOGTYPEERROR, "onPurchaseResponse: FAILED");
          observer.handlePurchaseError(new Throwable("onPurchaseResponse: FAILED"));
            break;
            
        case NOT_SUPPORTED:
          showMessage(LOGTYPEERROR,  "onPurchaseResponse: NOT_SUPPORTED so remove purchase request from local storage");
          observer.handlePurchaseError(new Throwable("onPurchaseResponse: NOT_SUPPORTED"));
            break;
        }
    }
//    }

    //=======================================================
    
    
    
  /** Converts a Receipt to our transaction object. */
  Transaction convertReceiptToTransaction (int i, String requestId, Receipt receipt, final UserData userData) {

    // build the transaction from the purchase object
    Transaction transaction = new Transaction();
    transaction.setIdentifier(receipt.getSku());
    transaction.setOrderId(receipt.getReceiptId());
    transaction.setStoreName(storeName());
    transaction.setRequestId(requestId);
    transaction.setUserId(userData.getUserId());
    transaction.setPurchaseTime(receipt.getPurchaseDate());
    transaction.setPurchaseText("Purchased: " + receipt.getSku().toString());
    // transaction.setPurchaseCost(receipt.getSku()); // TODO: GdxPay: impl. parsing of COST + CURRENCY via skuDetails.getPrice()!
    // transaction.setPurchaseCostCurrency(null);

     if (receipt.isCanceled()) {
    // order has been refunded or cancelled
     transaction.setReversalTime(receipt.getCancelDate());
//     transaction.setReversalText(receipt..getPurchaseState() == 1 ? "Cancelled" : "Refunded");
     } else {
     // still valid!
       transaction.setReversalTime(null);
       transaction.setReversalText(null);
     }

     transaction.setTransactionData(receipt.toJSON().toString());
    // transaction.setTransactionDataSignature(purchase.getSignature());

    showMessage(LOGTYPELOG, "converted purchased product " + i + " to transaction.");
    return transaction;
  }
  
  @Override
  public String toString () {
    return storeName();
  }
}




Java Source Code List

com.badlogic.gdx.pay.Information.java
com.badlogic.gdx.pay.OfferType.java
com.badlogic.gdx.pay.Offer.java
com.badlogic.gdx.pay.PurchaseManagerConfig.java
com.badlogic.gdx.pay.PurchaseManager.java
com.badlogic.gdx.pay.PurchaseObserver.java
com.badlogic.gdx.pay.PurchaseSystem.java
com.badlogic.gdx.pay.Transaction.java
com.badlogic.gdx.pay.android.IAP.java
com.badlogic.gdx.pay.android.amazon.PurchaseManagerAndroidAmazon.java
com.badlogic.gdx.pay.android.openiab.PurchaseManagerAndroidOpenIAB.java
com.badlogic.gdx.pay.android.ouya.PurchaseManagerAndroidOUYA.java
com.badlogic.gdx.pay.desktop.apple.PurchaseManagerDesktopApple.java
com.badlogic.gdx.pay.gwt.googlewallet.PurchaseManagerGwtGoogleWallet.java
com.badlogic.gdx.pay.ios.apple.PurchaseManageriOSApple.java
com.badlogic.gdx.pay.server.PurchaseVerifierManager.java
com.badlogic.gdx.pay.server.PurchaseVerifier.java
com.badlogic.gdx.pay.server.impl.PurchaseVerifierAndroidAmazon.java
com.badlogic.gdx.pay.server.impl.PurchaseVerifierAndroidGoogle.java
com.badlogic.gdx.pay.server.impl.PurchaseVerifieriOSApple.java
com.badlogic.gdx.pay.server.util.Base64Util.java