jp.app_mart.billing.AppmartHelper.java Source code

Java tutorial

Introduction

Here is the source code for jp.app_mart.billing.AppmartHelper.java

Source

package jp.app_mart.billing;

import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.List;

import javax.crypto.Cipher;

import jp.app_mart.sample.R;
import jp.app_mart.service.AppmartInBillingInterface;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Base64;
import android.util.Log;

/**
 * appmart???
 * appmart??????aild???????
 * ??? http://appmart.jp/
 */
public class AppmartHelper {

    //?
    boolean mDebugLog = false;
    String mDebugTag = "IabHelper";

    //Appmart??       
    public static final String RESULT_CODE_STRING = "resultCode";
    public static final String BILLING_APPMART_PACKAGE_NAME = "jp.app_mart";
    public static final String BILLING_APPMART_SERVICE_NAME = "jp.app_mart.service.AppmartInBillingService";
    public static final int BILLING_RESPONSE_RESULT_OK = 1;
    public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 91;
    public static final int BILLING_CONFIRM_TRANSACTION_FAILED = 92;
    public static final int APPMARTHELPER_GET_BUNDLE_FOR_PAYMENT_FAILED = 93;
    public static final int APPMARTHELPER_SEND_INTENT_FAILED = 94;
    public static final int APPMARTHELPER_REMOTE_EXCEPTION = 95;
    public static final int APPMARTHELPER_JSON_EXCEPTION = 96;
    public static final int APPMARTHELPER_BAD_RESPONSE = 97;
    public static final int APPMARTHELPER_INTERRUPTED = 98;
    public static final int APPMARTHELPER_EXCEPTION = 101;

    //
    public Context mContext;

    //???
    public String mDeveloperId;
    public String mLicenseKey;
    public String mSignatureBase64;
    public String mAppId;
    public String resultKey;

    //aidl????
    public AppmartInBillingInterface mService;

    //???ServiceConnection
    public ServiceConnection mServiceConn;

    //?
    public AppmartReceiver mReceiver;

    //
    public boolean mSetupDone = false;

    //
    public boolean mAsyncInProgress = false;
    public String mAsyncOperation = "";
    public OnAppmartPurchaseFinishedListener mPurchaseListener;

    //??
    public String mPurchasingItemType;
    public String mPurchasingSku;

    /**
     * Constructor
     * @param ctx
     * @param developerId
     * @param licenseKey
     * @param base64PublicKey
     * @param appId
     */
    public AppmartHelper(Context ctx, String developerId, String licenseKey, String base64PublicKey, String appId) {

        mContext = ctx;
        mDeveloperId = developerId;
        mLicenseKey = licenseKey;
        mSignatureBase64 = base64PublicKey;
        mAppId = appId;
    }

    /**
     * Debug
     * @param enable
     * @param tag
     */
    public void enableDebugLogging(boolean enable, String tag) {
        mDebugLog = enable;
        mDebugTag = tag;
    }

    public void enableDebugLogging(boolean enable) {
        mDebugLog = enable;
    }

    /**
     * callback?
     * {@link #onAppmartSetupFinished}?????
     */
    public interface OnAppmartSetupFinishedListener {
        public void onAppmartSetupFinished(AppmartResult result);
    }

    /**
     * appmart???
     * @param listener Activity?callback
     */
    public void startSetup(final OnAppmartSetupFinishedListener listener) {

        if (mSetupDone)
            throw new IllegalStateException(mContext.getString(R.string.already_connected));

        mServiceConn = new ServiceConnection() {

            //?
            public void onServiceConnected(ComponentName name, IBinder boundService) {
                mService = AppmartInBillingInterface.Stub.asInterface((IBinder) boundService);
                mSetupDone = true;
                if (listener != null) {
                    listener.onAppmartSetupFinished(new AppmartResult(BILLING_RESPONSE_RESULT_OK,
                            mContext.getString(R.string.is_now_connected)));
                }

                //????receiver
                IntentFilter filter = new IntentFilter("appmart_broadcast_return_service_payment");
                if (mReceiver == null)
                    mReceiver = new AppmartReceiver();
                mContext.registerReceiver(mReceiver, filter);
            }

            //?
            public void onServiceDisconnected(ComponentName name) {
                logDebug(mContext.getString(R.string.is_now_deconnected));
                mService = null;
            }
        };

        Intent serviceIntent = new Intent();
        serviceIntent.setClassName(BILLING_APPMART_PACKAGE_NAME, BILLING_APPMART_SERVICE_NAME);

        //?appmart????????
        if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) {

            mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);

        } else {

            if (listener != null) {
                listener.onAppmartSetupFinished(new AppmartResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE,
                        mContext.getString(R.string.appmart_not_installed)));
            }
        }
    }

    /**
     * ???
     */
    public void dispose() {
        mSetupDone = false;
        if (mServiceConn != null) {
            if (mContext != null) {
                mContext.unregisterReceiver(mReceiver);
                mReceiver = null;
                mContext.unbindService(mServiceConn);
            }
            mServiceConn = null;
            mService = null;
            mPurchaseListener = null;
        }
    }

    /**
     * ?callback
     */
    public interface OnAppmartPurchaseFinishedListener {
        public void onAppmartPurchaseFinished(AppmartResult result, Payment info);
    }

    /**
     * ??
     * @param act
     * @param sku
     * @param requestCode
     * @param listener
     */
    public void launchPurchaseFlow(final Activity act, final String sku, final int requestCode,
            final OnAppmartPurchaseFinishedListener listener) {

        final String itemType = "0";

        checkSetupDone("launchPurchaseFlow");

        (new Thread(new Runnable() {
            public void run() {

                logDebug(mContext.getString(R.string.get_information) + sku);
                AppmartResult result;

                try {
                    Context context = mContext.getApplicationContext();
                    String dataEncrypted = createEncryptedData(sku, mDeveloperId, mLicenseKey, mSignatureBase64);
                    Bundle bundleForPaymentInterface = mService.prepareForBillingService(mAppId, dataEncrypted);

                    if (bundleForPaymentInterface == null) {

                        logError(mContext.getString(R.string.bundle_unreachable));

                        result = new AppmartResult(APPMARTHELPER_GET_BUNDLE_FOR_PAYMENT_FAILED,
                                mContext.getString(R.string.bundle_unreachable));

                        if (listener != null)
                            listener.onAppmartPurchaseFinished(result, null);
                        return;
                    }

                    int response = bundleForPaymentInterface.getInt("resultCode");

                    if (response != BILLING_RESPONSE_RESULT_OK) {

                        logError(mContext.getString(R.string.response_code_error) + response);
                        result = new AppmartResult(response, mContext.getString(R.string.product_not_purchasable));

                        if (listener != null)
                            listener.onAppmartPurchaseFinished(result, null);
                        return;
                    }

                    // ?
                    resultKey = bundleForPaymentInterface.getString("resultKey");

                    PendingIntent pIntent = bundleForPaymentInterface.getParcelable("appmart_pending_intent");
                    mPurchaseListener = listener;
                    mPurchasingItemType = itemType;
                    mPurchasingSku = sku;
                    pIntent.send(context, 0, new Intent());

                } catch (RemoteException e) {

                    logError(mContext.getString(R.string.failed_prepare_bill_service));

                    result = new AppmartResult(APPMARTHELPER_SEND_INTENT_FAILED,
                            mContext.getString(R.string.failed_sending_intent));

                    if (listener != null)
                        listener.onAppmartPurchaseFinished(result, null);

                } catch (PendingIntent.CanceledException e) {

                    logError(mContext.getString(R.string.failed_sending_intent));

                    result = new AppmartResult(APPMARTHELPER_SEND_INTENT_FAILED,
                            mContext.getString(R.string.failed_sending_intent));

                    if (listener != null)
                        listener.onAppmartPurchaseFinished(result, null);
                }
            }
        })).start();
    }

    /**
     * Broadcast Receiver
     * ????
     */
    private class AppmartReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(final Context arg0, final Intent arg1) {

            (new Thread(new Runnable() {
                public void run() {

                    AppmartResult result;
                    try {

                        //
                        String resultKeyCurrentStransaction = arg1.getExtras().getString("appmart_result_key");
                        if (resultKeyCurrentStransaction == null
                                || resultKeyCurrentStransaction.equals(resultKey)) {

                            Thread.sleep(1000);

                            // ?
                            final String transactionId = arg1.getExtras().getString("appmart_service_trns_id");

                            int res = mService.confirmFinishedTransaction(transactionId, mPurchasingSku,
                                    mDeveloperId);

                            if (res != BILLING_RESPONSE_RESULT_OK) {
                                result = new AppmartResult(BILLING_CONFIRM_TRANSACTION_FAILED, "ErrorCode:" + res
                                        + " (" + transactionId + ", " + mPurchasingSku + ", " + mDeveloperId + ")");
                                if (mPurchaseListener != null)
                                    mPurchaseListener.onAppmartPurchaseFinished(result, null);
                                return;
                            }

                            String json = mService.getPaymentDetails(transactionId, mPurchasingSku, mDeveloperId);
                            logDebug("Payment details: " + json);

                            Payment payment = new Payment(mPurchasingItemType, mPurchasingSku, json, transactionId);
                            result = new AppmartResult(BILLING_RESPONSE_RESULT_OK, null);

                            if (mPurchaseListener != null)
                                mPurchaseListener.onAppmartPurchaseFinished(result, payment);

                        }

                    } catch (RemoteException e) {
                        result = new AppmartResult(APPMARTHELPER_REMOTE_EXCEPTION, null);
                        if (mPurchaseListener != null)
                            mPurchaseListener.onAppmartPurchaseFinished(result, null);
                        e.printStackTrace();
                    } catch (JSONException e) {
                        result = new AppmartResult(APPMARTHELPER_JSON_EXCEPTION, null);
                        if (mPurchaseListener != null)
                            mPurchaseListener.onAppmartPurchaseFinished(result, null);
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        result = new AppmartResult(APPMARTHELPER_INTERRUPTED, null);
                        if (mPurchaseListener != null)
                            mPurchaseListener.onAppmartPurchaseFinished(result, null);
                    } catch (Exception e) {
                        result = new AppmartResult(APPMARTHELPER_EXCEPTION, null);
                        if (mPurchaseListener != null)
                            mPurchaseListener.onAppmartPurchaseFinished(result, null);
                    }

                }

            })).start();
        }
    }

    /**
     * 
     * @param querySkuDetails
     * @param moreSkus
     * @return
     * @throws AppmartException
     */
    public AppmartInventory queryInventory(boolean querySkuDetails, List<String> moreSkus) throws AppmartException {
        return queryInventory(querySkuDetails, moreSkus, null);
    }

    public interface QueryAppmartInventoryFinishedListener {
        public void onQueryInventoryFinished(AppmartResult result, AppmartInventory inv);
    }

    /**
     * thread??
     * @param querySkuDetails
     * @param moreSkus
     * @param listener
     */
    public void queryInventoryAsync(final List<String> moreSkus,
            final QueryAppmartInventoryFinishedListener listener) {

        final Handler handler = new Handler();

        checkSetupDone("queryInventory");
        flagStartAsync("refresh inventory");

        (new Thread(new Runnable() {

            public void run() {

                AppmartResult result = new AppmartResult(BILLING_RESPONSE_RESULT_OK,
                        mContext.getString(R.string.inventory_refreshed));
                AppmartInventory inv = null;

                try {
                    inv = queryInventory(true, moreSkus);
                } catch (AppmartException ex) {
                    result = ex.getResult();
                }

                flagEndAsync();

                final AppmartResult result_f = result;
                final AppmartInventory inv_f = inv;
                handler.post(new Runnable() {
                    public void run() {
                        listener.onQueryInventoryFinished(result_f, inv_f);
                    }
                });
            }
        })).start();

    }

    /**
     * 
     * @param querySkuDetails
     * @param moreItemSkus
     * @param moreSubsSkus
     * @return
     * @throws AppmartException
     */
    public AppmartInventory queryInventory(boolean querySkuDetails, List<String> moreItemSkus,
            List<String> moreSubsSkus) throws AppmartException {

        checkSetupDone("queryInventory");

        try {
            AppmartInventory inv = new AppmartInventory();

            if (querySkuDetails) {
                int r = querySkuDetails(inv, moreItemSkus);
                if (r != BILLING_RESPONSE_RESULT_OK) {
                    throw new AppmartException(r, mContext.getString(R.string.inventory_refreshed_error));
                }
            }

            return inv;

        } catch (RemoteException e) {
            throw new AppmartException(APPMARTHELPER_REMOTE_EXCEPTION,
                    mContext.getString(R.string.inventory_refreshed_error_remote), e);
        } catch (JSONException e) {
            throw new AppmartException(APPMARTHELPER_BAD_RESPONSE,
                    mContext.getString(R.string.inventory_refreshed_error_json), e);
        }
    }

    /**
     * ????AppmartInventory?
     * @param inv         ?
     * @param serviceIds   ?
     * @throws RemoteException
     * @throws JSONException
     */
    int querySkuDetails(AppmartInventory inv, List<String> serviceIds) throws RemoteException, JSONException {

        logDebug(mContext.getString(R.string.get_inventory));

        int response = BILLING_RESPONSE_RESULT_OK;

        //????
        for (String serviceId : serviceIds) {

            String json = mService.getServiceDetails(mAppId,
                    createEncryptedData(serviceId, mDeveloperId, mLicenseKey, mSignatureBase64));

            //JSON?
            JSONObject o = new JSONObject(json);

            //??
            int tmpResponse = Integer.valueOf(o.optString(RESULT_CODE_STRING));
            if (tmpResponse != BILLING_RESPONSE_RESULT_OK) {
                response = tmpResponse;
            }

            ServiceDetails details = new ServiceDetails(json);
            inv.addServiceDetails(details);
        }

        return response;
    }

    /**
     * ?
     * @param serviceId
     * @param developId
     * @param strLicenseKey
     * @param strPublicKey
     * @return
     */
    public static String createEncryptedData(String serviceId, String developId, String strLicenseKey,
            String strPublicKey) {
        final String SEP_SYMBOL = "&";
        StringBuilder infoDataSB = new StringBuilder();
        infoDataSB.append(serviceId).append(SEP_SYMBOL);
        // ?ID 
        infoDataSB.append(developId).append(SEP_SYMBOL);
        // 
        infoDataSB.append(strLicenseKey);
        String strEncryInfoData = "";
        try {
            KeyFactory keyFac = KeyFactory.getInstance("RSA");
            KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(strPublicKey.getBytes(), Base64.DEFAULT));
            Key publicKey = keyFac.generatePublic(keySpec);
            if (publicKey != null) {
                Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                byte[] EncryInfoData = cipher.doFinal(infoDataSB.toString().getBytes());
                strEncryInfoData = new String(Base64.encode(EncryInfoData, Base64.DEFAULT));
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            strEncryInfoData = "";
            Log.e("AppmartHelper", "?");
        }
        return strEncryInfoData.replaceAll("(\\r|\\n)", "");
    }

    /**
     * ??????
     * @param operation
     */
    void checkSetupDone(String operation) {
        if (!mSetupDone) {
            throw new IllegalStateException("?????" + operation);
        }
    }

    /**
     * 
     * @param operation
     */
    void flagStartAsync(String operation) {
        if (mAsyncInProgress)
            throw new IllegalStateException("Can't start async operation (" + operation
                    + ") because another async operation(" + mAsyncOperation + ") is in progress.");
        mAsyncOperation = operation;
        mAsyncInProgress = true;
        logDebug("Starting async operation: " + operation);
    }

    /**
     * 
     */
    void flagEndAsync() {
        logDebug("Ending async operation: " + mAsyncOperation);
        mAsyncOperation = "";
        mAsyncInProgress = false;
    }

    /**
     * ??
     * @param code
     * @return
     */
    public static String getResponseDesc(int code) {
        switch (code) {
        case BILLING_CONFIRM_TRANSACTION_FAILED:
            return "Confirm transaction failed";
        case APPMARTHELPER_REMOTE_EXCEPTION:
            return "Remote exception";
        case APPMARTHELPER_JSON_EXCEPTION:
            return "JSON exception";
        case APPMARTHELPER_INTERRUPTED:
            return "Thread error";
        default:
            return "tmp message";
        }
    }

    void logDebug(String msg) {
        if (mDebugLog)
            Log.d(mDebugTag, msg);
    }

    void logError(String msg) {
        Log.e(mDebugTag, "In-app billing error: " + msg);
    }

    void logWarn(String msg) {
        Log.w(mDebugTag, "In-app billing warning: " + msg);
    }

}