com.oasis.sdk.activity.GooglePlayBillingActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.oasis.sdk.activity.GooglePlayBillingActivity.java

Source

/* Copyright (c) 2012 Google Inc.
 *
 * 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.oasis.sdk.activity;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.oasis.sdk.OASISPlatformConstant;
import com.oasis.sdk.OasisCallback;
import com.oasis.sdk.base.Exception.OasisSdkException;
import com.oasis.sdk.base.entity.PayInfoDetail;
import com.oasis.sdk.base.entity.PayInfoList;
import com.oasis.sdk.base.entity.PhoneInfo;
import com.oasis.sdk.base.entity.ReportAdjustInfo;
import com.oasis.sdk.base.report.ReportUtils;
import com.oasis.sdk.base.service.HttpService;
import com.oasis.sdk.base.utils.BaseUtils;
import com.oasis.sdk.base.utils.MD5Encrypt;
import com.oasis.sdk.base.utils.SystemCache;
import com.oasis.sdk.pay.googleplay.utils.GoogleBillingUtils;
import com.oasis.sdk.pay.googleplay.utils.IabHelper;
import com.oasis.sdk.pay.googleplay.utils.IabHelper.QueryInventoryFinishedListener;
import com.oasis.sdk.pay.googleplay.utils.IabResult;
import com.oasis.sdk.pay.googleplay.utils.Inventory;
import com.oasis.sdk.pay.googleplay.utils.Purchase;
import com.oasis.sdk.pay.googleplay.utils.SkuDetails;

/**
 * Example game using in-app billing version 3.
 *
 * Before attempting to run this sample, please read the README file. It
 * contains important information on how to set up this project.
 *
 * All the game-specific logic is implemented here in MainActivity, while the
 * general-purpose boilerplate that can be reused in any app is provided in the
 * classes in the util/ subdirectory. When implementing your own application,
 * you can copy over util/*.java to make use of those utility classes.
 *
 * This game is a simple "driving" game where the player can buy gas
 * and drive. The car has a tank which stores gas. When the player purchases
 * gas, the tank fills up (1/4 tank at a time). When the player drives, the gas
 * in the tank diminishes (also 1/4 tank at a time).
 *
 * The user can also purchase a "premium upgrade" that gives them a red car
 * instead of the standard blue one (exciting!).
 *
 * The user can also purchase a subscription ("infinite gas") that allows them
 * to drive without using up any gas while that subscription is active.
 *
 * It's important to note the consumption mechanics for each item.
 *
 * PREMIUM: the item is purchased and NEVER consumed. So, after the original
 * purchase, the player will always own that item. The application knows to
 * display the red car instead of the blue one because it queries whether
 * the premium "item" is owned or not.
 *
 * INFINITE GAS: this is a subscription, and subscriptions can't be consumed.
 *
 * GAS: when gas is purchased, the "gas" item is then owned. We consume it
 * when we apply that item's effects to our app's world, which to us means
 * filling up 1/4 of the tank. This happens immediately after purchase!
 * It's at this point (and not when the user drives) that the "gas"
 * item is CONSUMED. Consumption should always happen when your game
 * world was safely updated to apply the effect of the purchase. So,
 * in an example scenario:
 *
 * BEFORE:      tank at 1/2
 * ON PURCHASE: tank at 1/2, "gas" item is owned
 * IMMEDIATELY: "gas" is consumed, tank goes to 3/4
 * AFTER:       tank at 3/4, "gas" item NOT owned any more
 *
 * Another important point to notice is that it may so happen that
 * the application crashed (or anything else happened) after the user
 * purchased the "gas" item, but before it was consumed. That's why,
 * on startup, we check if we own the "gas" item, and, if so,
 * we have to apply its effects to our world and consume it. This
 * is also very important!
 *
 * @author Bruno Oliveira (Google)
 */
public class GooglePlayBillingActivity extends OasisSdkBaseActivity {
    // Debug tag, for logging
    static final String TAG = "GooglePlayBilling";

    private String base64EncodedPublicKey = "";

    // (arbitrary) request code for the purchase flow
    static final int RC_REQUEST = 10001;
    // ?google play ??
    static final int RC_VERIFYGOOGLEPLAY = 10002;

    // The helper object
    IabHelper mHelper;

    String productID;
    String revenue;
    String oasOrderid = "";
    String ext = "";// ????
    MyHandler myHandler;
    List<Purchase> oldOrderList = null;//??
    List<String> handedOrderIDS = new ArrayList<String>();//????

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(BaseUtils.getResourceValue("layout", "oasisgames_sdk_pay_google"));

        myHandler = new MyHandler(this);

        /* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
         * (that you got from the Google Play developer console). This is not your
         * developer public key, it's the *app-specific* public key.
         *
         * Instead of just storing the entire literal string here embedded in the
         * program,  construct the key at runtime from pieces or
         * use bit manipulation (for example, XOR with some other string) to hide
         * the actual key.  The key itself is not secret information, but we don't
         * want to make it easy for an attacker to replace the public key with one
         * of their own and then fake messages from the server.
         */
        //        String base64EncodedPublicKey = "CONSTRUCT_YOUR_KEY_AND_PLACE_IT_HERE";

        if (TextUtils.isEmpty(base64EncodedPublicKey)) {
            ApplicationInfo appInfo;
            try {
                appInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
                base64EncodedPublicKey = appInfo.metaData.getString("com.googleplay.ApplicationId");
            } catch (NameNotFoundException e) {
                BaseUtils.logDebug(TAG, "Please put your app's public key in AndroidManifest.xml.");
            }
        }
        if (TextUtils.isEmpty(base64EncodedPublicKey)) {
            BaseUtils.logError(TAG, "Please put your app's public key in AndroidManifest.xml.");
            complain("Please put your app's public key in AndroidManifest.xml.");
            return;
        }

        productID = getIntent().getStringExtra("inAppProductID");
        ext = getIntent().getStringExtra("ext");
        oasOrderid = getIntent().getStringExtra("oasOrderid");
        if (TextUtils.isEmpty(productID)) {
            BaseUtils.logError(TAG, "Please put product id.");
            complain("Please put product id.");
            return;
        }

        if (SystemCache.userInfo == null || TextUtils.isEmpty(SystemCache.userInfo.serverID)
                || TextUtils.isEmpty(SystemCache.userInfo.roleID)) {
            BaseUtils.logError(TAG, "Please put game serverid or roleid.");
            complain("Please put game server id.");
            return;
        }

        //        revenue = getRevenueAndCurrency();// ?productid?????
        //        if(TextUtils.isEmpty(revenue)){
        //           BaseUtils.logError(TAG, "This product id does not exist, please contact customer support");
        //           setResult(OASISPlatformConstant.RESULT_EXCEPTION);
        //           Message msg = new Message();
        //           msg.what = 0;
        //           msg.obj = getResources().getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_2")); 
        //            myHandler.sendMessage(msg);
        //           return;
        //        }
        setWaitScreen(true);

        if (SystemCache.OASISSDK_ENVIRONMENT_SANDBOX) {
            initSandBox();
            //1  ? ??
            //2 ???
            //3 ??
            return;
        }
        // Create the helper, passing it our context and the public key to verify signatures with
        BaseUtils.logDebug(TAG, "Creating IAB helper.");
        mHelper = new IabHelper(this.getApplicationContext(), base64EncodedPublicKey);

        // enable debug logging (for a production application, you should set this to false).
        mHelper.enableDebugLogging(SystemCache.OASISSDK_ENVIRONMENT_SANDBOX);

        int isGoolgePlayAvail = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this.getApplicationContext());
        if (isGoolgePlayAvail == ConnectionResult.SUCCESS) {
            // Start setup. This is asynchronous and the specified listener
            // will be called once setup completes.
            BaseUtils.logDebug(TAG, "Starting setup.");
            mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
                public void onIabSetupFinished(IabResult result) {
                    if (isPageClose()) {
                        isPageCloseHandler();
                        return;
                    }
                    BaseUtils.logDebug(TAG, "Setup finished.");

                    if (!result.isSuccess()) {
                        // Oh noes, there was a problem.
                        BaseUtils.logError(TAG, "Problem setting up in-app billing: "
                                + IabHelper.getResponseDesc(result.getResponse()));
                        Message msg = new Message();
                        msg.what = 0;
                        msg.obj = getResources().getString(
                                BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_1"));
                        myHandler.sendMessage(msg);
                        return;
                    }

                    // Have we been disposed of in the meantime? If so, quit.
                    if (mHelper == null)
                        return;

                    // IAB is fully set up. Now, Start purchase.
                    try {
                        oldOrderList = GoogleBillingUtils.getPurchasedList();
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    //                queryInventory();
                    checkALLOrder(0);
                }
            });
        } else {

            Dialog d = GooglePlayServicesUtil.getErrorDialog(isGoolgePlayAvail, this, RC_VERIFYGOOGLEPLAY);
            d.setOnDismissListener(new OnDismissListener() {

                @Override
                public void onDismiss(DialogInterface arg0) {
                    BaseUtils.logError(TAG, "GooglePlayServicesUtil.showErrorDialogFragment");
                    arg0.dismiss();

                    myHandler.sendEmptyMessageDelayed(-1, 500);
                }
            });
            d.show();

        }
    }

    /**
     * ??
     */
    private void checkALLOrder(final int index) {
        new Thread(new Runnable() {

            @Override
            public void run() {

                if (oldOrderList == null || oldOrderList.size() <= 0 || index >= oldOrderList.size()) {
                    myHandler.sendEmptyMessage(101);//?
                    return;
                }

                Purchase purchase = oldOrderList.get(index);
                if (handedOrderIDS.contains(purchase.getOrderId())) {// ?orderid??
                    Message msg = new Message();
                    msg.what = 98;
                    msg.arg1 = index;
                    myHandler.sendMessage(msg);//?
                    return;
                } else
                    handedOrderIDS.add(purchase.getOrderId());

                Message msg = null;

                msg = new Message();
                msg.what = -2;
                msg.obj = getResources()
                        .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_order_notice_old"));// ????
                myHandler.sendMessage(msg);
                int res = -1;
                try {
                    res = HttpService.instance().checkPurchaseForGoogle(purchase, GoogleBillingUtils.SEPARATE);

                    msg = new Message();
                    switch (res) {
                    case 1000000://???
                    case 1000002://?????2?
                    case 1000006://?Google??
                    case 1000001://sign?????
                        msg.what = 99;
                        msg.obj = purchase;
                        msg.arg1 = res;
                        myHandler.sendMessage(msg);
                        break;

                    default:
                        msg.what = 98;
                        msg.arg1 = index;
                        myHandler.sendMessage(msg);//?
                        break;
                    }

                } catch (OasisSdkException e) {// ??
                    msg = new Message();
                    msg.what = 98;
                    msg.arg1 = index;
                    myHandler.sendMessage(msg);//?
                } finally {
                    try {
                        String[] info = purchase.getDeveloperPayload().split(GoogleBillingUtils.SEPARATE);

                        // ?Mdata???
                        List<String> parameters = new ArrayList<String>();
                        parameters.add("\"uid\":\"" + info[0] + "\"");
                        parameters.add("\"roleid\":\"" + info[2] + "\"");
                        parameters.add("\"serverid\":\"" + info[1] + "\"");
                        if (info.length >= 6 && ("android".equalsIgnoreCase(info[5])
                                || "all".equalsIgnoreCase(info[5]) || "test".equalsIgnoreCase(info[5])))
                            parameters.add("\"servertype\":\"" + info[5] + "\"");
                        else
                            parameters.add("\"servertype\":\"\"");
                        parameters.add("\"product_id\":\"" + purchase.getSku() + "\"");
                        parameters.add("\"payment_channal\":\"mob_google\"");
                        String re = info[4];
                        if (re != null && !TextUtils.isEmpty(re)) {
                            String[] rev = re.split("_");
                            parameters.add("\"cost\":\"" + (rev.length > 0 ? rev[0] : "") + "\"");
                            parameters.add("\"currency\":\"" + (rev.length > 1 ? rev[1] : "") + "\"");
                        } else {
                            parameters.add("\"cost\":\"\"");
                            parameters.add("\"currency\":\"\"");
                        }
                        parameters.add("\"value\":\"\"");
                        if (info.length >= 7)
                            parameters.add("\"oas_order_id\":\"" + info[6] + "\"");
                        else
                            parameters.add("\"oas_order_id\":\"\"");
                        parameters.add("\"third_party_orderid\":\"" + purchase.getOrderId() + "\"");
                        parameters.add("\"result_code\":\"" + res + "\"");
                        parameters.add("\"isreport\":\"" + (PhoneInfo.instance().isTrackAble() ? "Y" : "N") + "\"");

                        List<String> status = new ArrayList<String>();
                        status.add("\"event_type\":\"order\"");
                        ReportUtils.add(ReportUtils.DEFAULTEVENT_ORDER_REPORT_OLD_LOCAL, parameters, status);
                    } catch (Exception e) {
                        BaseUtils.logError(TAG, "Google play billing send mdata fail.");
                    }
                } //end try
            }//end run
        }).start();
    }

    private void queryInventory() {
        if (isPageClose()) {
            isPageCloseHandler();
            return;
        }
        List<String> moreSkus = new ArrayList<String>();
        moreSkus.add(productID);
        mHelper.queryInventoryAsync(true, moreSkus, new QueryInventoryFinishedListener() {

            @Override
            public void onQueryInventoryFinished(IabResult result, Inventory inv) {
                if (isPageClose()) {
                    isPageCloseHandler();
                    return;
                }
                // Is it a failure?
                if (result.isFailure() || inv == null) {
                    BaseUtils.logError(TAG,
                            "Failed to query inventory: " + IabHelper.getResponseDesc(result.getResponse()));
                    Message msg = new Message();
                    msg.what = 0;
                    msg.obj = getResources()
                            .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_2"));
                    myHandler.sendMessage(msg);
                    return;
                }

                SkuDetails sku = inv.getSkuDetails(productID);
                if (sku == null || TextUtils.isEmpty(sku.getPrice())) {
                    BaseUtils.logError(TAG, "Don't find SkuDetails by " + productID);
                    Message msg = new Message();
                    msg.what = 0;
                    msg.obj = getResources()
                            .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_2"));
                    myHandler.sendMessage(msg);
                    return;
                }

                final Purchase p = inv.getPurchase(productID);
                if (p == null || (p != null && p.getPurchaseState() != IabHelper.BILLING_RESPONSE_RESULT_OK
                        && p.getPurchaseState() != IabHelper.BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED)) {

                    if (p != null && p.getPurchaseState() == IabHelper.BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED) {
                        inv.erasePurchase(productID);
                    }
                    BaseUtils.logDebug(TAG, "Old purchase is null. Start purchase.");

                    startPurchase();
                    return;
                }
                //????
                Message msg = new Message();
                msg.what = -2;
                msg.obj = getResources()
                        .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_order_notice_old"));
                myHandler.sendMessage(msg);
                new Thread(new Runnable() {

                    @Override
                    public void run() {

                        BaseUtils.logDebug(TAG, "Old purchase info:" + p.toString());
                        int res = -1;
                        try {
                            res = HttpService.instance().checkPurchaseForGoogle(p, GoogleBillingUtils.SEPARATE);
                        } catch (OasisSdkException e) {

                        } finally {
                            try {
                                String[] info = p.getDeveloperPayload().split(GoogleBillingUtils.SEPARATE);

                                // ?Mdata???
                                List<String> parameters = new ArrayList<String>();
                                parameters.add("\"uid\":\"" + info[0] + "\"");
                                parameters.add("\"roleid\":\"" + info[2] + "\"");
                                parameters.add("\"serverid\":\"" + info[1] + "\"");
                                if (info.length >= 6 && ("android".equalsIgnoreCase(info[5])
                                        || "all".equalsIgnoreCase(info[5]) || "test".equalsIgnoreCase(info[5])))
                                    parameters.add("\"servertype\":\"" + info[5] + "\"");
                                else
                                    parameters.add("\"servertype\":\"\"");
                                parameters.add("\"product_id\":\"" + p.getSku() + "\"");
                                parameters.add("\"payment_channal\":\"mob_google\"");
                                String re = info[4];
                                if (re != null && !TextUtils.isEmpty(re)) {
                                    String[] rev = re.split("_");
                                    parameters.add("\"cost\":\"" + (rev.length > 0 ? rev[0] : "") + "\"");
                                    parameters.add("\"currency\":\"" + (rev.length > 1 ? rev[1] : "") + "\"");
                                } else {
                                    parameters.add("\"cost\":\"\"");
                                    parameters.add("\"currency\":\"\"");
                                }
                                parameters.add("\"value\":\"\"");
                                if (info.length >= 7)
                                    parameters.add("\"oas_order_id\":\"" + info[6] + "\"");
                                else
                                    parameters.add("\"oas_order_id\":\"\"");
                                parameters.add("\"third_party_orderid\":\"" + p.getOrderId() + "\"");
                                parameters.add("\"result_code\":\"" + res + "\"");
                                parameters.add("\"isreport\":\"" + (PhoneInfo.instance().isTrackAble() ? "Y" : "N")
                                        + "\"");

                                List<String> status = new ArrayList<String>();
                                status.add("\"event_type\":\"order\"");
                                ReportUtils.add(ReportUtils.DEFAULTEVENT_ORDER_REPORT_OLD_GOOGLE, parameters,
                                        status);
                            } catch (Exception e) {
                                BaseUtils.logError(TAG, "Google play billing send mdata fail.");
                            }

                            BaseUtils.logDebug(TAG,
                                    "Old purchase handle.purchase.orderID=" + p.getOrderId() + ", Code=" + res);
                            if (isPageClose()) {
                                isPageCloseHandler();
                                return;
                            }
                            Message msg = new Message();
                            if (res == 1000000 || res == 1000002 || res == 1000006) {
                                msg.what = 100;
                                msg.obj = p;
                                msg.arg1 = -1;
                                myHandler.sendMessage(msg);

                            } else {
                                BaseUtils.logError(TAG, "???GoogleOrderid="
                                        + p.getOrderId() + ", Result Code=" + res + "");
                                //????
                                msg.what = 0;
                                msg.obj = getResources().getString(
                                        BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_error_fail"));
                                myHandler.sendMessage(msg);
                            }
                        }

                    }
                }).start();

            }
        });
    }

    /**
     * 
     */
    private void startPurchase() {
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                if (TextUtils.isEmpty(oasOrderid)) {// OAS orderid ?
                    if (!TextUtils.isEmpty(ext)) {
                        sendOrder();
                        return;
                    }
                    if (SystemCache.oasisInterface != null) {
                        SystemCache.oasisInterface.getExtendValue(new MyOasisCallbackForExt());
                    } else {
                        BaseUtils.logError(TAG,
                                "OASISPlatformsetOASISPlatformInterfaceImpl()???");

                        myHandler.sendEmptyMessage(HANDLER_FAIL);
                    }
                } else
                    launchPurchaseFlow();
            }
        });

    }

    class MyOasisCallbackForExt implements OasisCallback {

        @Override
        public void success(final String result) {
            ext = result;
            sendOrder();// ??ext????
        }

        @Override
        public void error(String result) {
            BaseUtils.logError(TAG, "?ext???.\n" + result);
            myHandler.sendEmptyMessage(HANDLER_FAIL);
        }

    }

    private void sendOrder() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                if (SystemCache.payInfoLists == null || SystemCache.payInfoLists.isEmpty()) {
                    try {// ?????
                        HttpService.instance().getPayKindsInfo(null);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                // ?ext????
                try {
                    int index = productID.lastIndexOf("_");
                    String id = productID.substring(index + 1);
                    oasOrderid = HttpService.instance().sendOrder(id, (TextUtils.isEmpty(ext) ? "" : ext));
                    if (TextUtils.isEmpty(oasOrderid)) {
                        BaseUtils.logError(TAG,
                                "??productID=" + productID + ", serverID="
                                        + SystemCache.userInfo.serverID + ", roleID=" + SystemCache.userInfo.roleID
                                        + ", ext=" + ext);
                        myHandler.sendEmptyMessage(HANDLER_FAIL);
                        return;
                    }
                    try {
                        List<String> parameters = new ArrayList<String>();
                        parameters.add("\"uid\":\"" + SystemCache.userInfo.uid + "\"");
                        parameters.add("\"roleid\":\"" + SystemCache.userInfo.roleID + "\"");
                        parameters.add("\"serverid\":\"" + SystemCache.userInfo.serverID + "\"");
                        parameters.add("\"servertype\":\"" + SystemCache.userInfo.serverType + "\"");
                        parameters.add("\"product_id\":\"" + productID + "\"");
                        parameters.add("\"payment_channal\":\"google\"");
                        if (revenue != null && !TextUtils.isEmpty(revenue)) {
                            String[] re = revenue.split("_");
                            parameters.add("\"cost\":\"" + (re.length > 0 ? re[0] : "") + "\"");
                            parameters.add("\"currency\":\"" + (re.length > 1 ? re[1] : "") + "\"");
                        } else {
                            parameters.add("\"cost\":\"\"");
                            parameters.add("\"currency\":\"\"");
                        }
                        parameters.add("\"value\":\"\"");
                        parameters.add("\"oas_order_id\":\"" + oasOrderid + "\"");
                        parameters.add("\"third_party_orderid\":\"\"");
                        parameters.add("\"result_code\":\"ok\"");
                        parameters.add("\"isreport\":\"" + (PhoneInfo.instance().isTrackAble() ? "Y" : "N") + "\"");

                        List<String> status = new ArrayList<String>();
                        status.add("\"event_type\":\"order\"");
                        ReportUtils.add(ReportUtils.DEFAULTEVENT_ORDER, parameters, status);
                    } catch (Exception e) {
                        Log.e(TAG, ReportUtils.DEFAULTEVENT_ORDER + "-> send mdata fail.");
                    }
                    startPurchase();
                } catch (OasisSdkException e) {
                    BaseUtils.logError(TAG,
                            "??productID=" + productID + ", serverID="
                                    + SystemCache.userInfo.serverID + ", roleID=" + SystemCache.userInfo.roleID
                                    + ", ext=" + ext);
                    myHandler.sendEmptyMessage(HANDLER_FAIL);
                }
            }
        }).start();
    }

    private String getRevenueAndCurrency() {
        String revenue = "";
        if (SystemCache.payInfoLists != null)
            for (PayInfoList payInfos : SystemCache.payInfoLists) {
                if ("mob_google".equals(payInfos.pay_way)) {
                    for (PayInfoDetail detail : payInfos.list) {
                        if (productID.equals(detail.price_product_id)) {
                            revenue = detail.amount + "_" + detail.currency;
                            break;
                        }
                    }
                    break;
                }
            }
        return revenue;
    }

    // ?google??
    private void launchPurchaseFlow() {
        if (isPageClose()) {
            isPageCloseHandler();
            return;
        }
        setWaitScreen(true);

        // V3.3???USD
        // V3.3?_? ?????Adjust?
        if (revenue == null || TextUtils.isEmpty(revenue))
            revenue = getRevenueAndCurrency();
        /* TODO: for security, generate your payload here for verification. See the comments on
         *        verifyDeveloperPayload() for more info. Since this is a SAMPLE, we just use
         *        an empty string, but on a production app you should carefully generate this. */

        String payload = SystemCache.userInfo.uid + GoogleBillingUtils.SEPARATE + SystemCache.userInfo.serverID
                + GoogleBillingUtils.SEPARATE + SystemCache.userInfo.roleID + GoogleBillingUtils.SEPARATE + ext
                + GoogleBillingUtils.SEPARATE + revenue + GoogleBillingUtils.SEPARATE
                + SystemCache.userInfo.serverType + GoogleBillingUtils.SEPARATE + oasOrderid
                + GoogleBillingUtils.SEPARATE
                + MD5Encrypt.StringToMD5(SystemCache.PAYKEY + SystemCache.GAMECODE + SystemCache.userInfo.serverID
                        + SystemCache.userInfo.uid + productID + (TextUtils.isEmpty(ext) ? "" : ext) + oasOrderid);

        BaseUtils.logDebug(TAG, "Start purchase " + productID);
        mHelper.launchPurchaseFlow(this, productID, RC_REQUEST, mPurchaseFinishedListener, payload);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        BaseUtils.logDebug(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
        if (mHelper == null)
            return;

        // Pass on the activity result to the helper for handling
        if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
            // not handled, so handle it ourselves (here's where you'd
            // perform any handling of activity results not related to in-app
            // billing...
            super.onActivityResult(requestCode, resultCode, data);
        } else {
            BaseUtils.logDebug(TAG, "onActivityResult handled by IABUtil.");
        }
    }

    /** Verifies the developer payload of a purchase. */
    boolean verifyDeveloperPayload(Purchase p) {
        if (p == null)
            return false;
        String payload = p.getDeveloperPayload();
        if (TextUtils.isEmpty(payload))
            return false;
        /*
         * TODO: verify that the developer payload of the purchase is correct. It will be
         * the same one that you sent when initiating the purchase.
         *
         * WARNING: Locally generating a random string when starting a purchase and
         * verifying it here might seem like a good approach, but this will fail in the
         * case where the user purchases an item on one device and then uses your app on
         * a different device, because on the other device you will not have access to the
         * random string you originally generated.
         *
         * So a good developer payload has these characteristics:
         *
         * 1. If two different users purchase an item, the payload is different between them,
         *    so that one user's purchase can't be replayed to another user.
         *
         * 2. The payload must be such that you can verify it even when the app wasn't the
         *    one who initiated the purchase flow (so that items purchased by the user on
         *    one device work on other devices owned by the user).
         *
         * Using your own server to store and verify developer payloads across app
         * installations is recommended.
         */
        payload = payload
                .substring(payload.lastIndexOf(GoogleBillingUtils.SEPARATE) + GoogleBillingUtils.SEPARATE.length());

        if (MD5Encrypt
                .StringToMD5(SystemCache.PAYKEY + SystemCache.GAMECODE + SystemCache.userInfo.serverID
                        + SystemCache.userInfo.uid + productID + (TextUtils.isEmpty(ext) ? "" : ext) + oasOrderid)
                .equals(payload))
            return true;

        return false;
    }

    // Callback for when a purchase is finished
    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
            BaseUtils.logDebug(TAG, "Purchase finished: " + result.toString() + ", purchase: " + purchase);
            boolean verify = verifyDeveloperPayload(purchase);
            // if we were disposed of in the meantime, quit.
            if (mHelper == null) {// ????
                if (result.isSuccess()) {
                    checkAndAddPurchase(purchase);
                    final Purchase pur = purchase;
                    if (verify) {// ?????? 
                        new Thread(new Runnable() {

                            @Override
                            public void run() {
                                try {
                                    HttpService.instance().checkPurchaseForGoogle(pur, GoogleBillingUtils.SEPARATE);
                                } catch (OasisSdkException e) {
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    }
                }
                return;
            }

            if (result.isFailure()) {
                BaseUtils.logError(TAG, "Error purchasing: " + IabHelper.getResponseDesc(result.getResponse()));
                if (result.getResponse() == -1005) {// User canceled
                    myHandler.sendEmptyMessage(-1);
                    setResultInfo(OASISPlatformConstant.RESULT_CANCLE, "User canceled");
                    return;
                }
                Message msg = new Message();
                msg.what = 0;
                msg.obj = getResources()
                        .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_3"));
                myHandler.sendMessage(msg);
                return;
            }
            try {
                String[] info = purchase.getDeveloperPayload().split(GoogleBillingUtils.SEPARATE);

                // ?Mdata???
                List<String> parameters = new ArrayList<String>();
                parameters.add("\"uid\":\"" + info[0] + "\"");
                parameters.add("\"roleid\":\"" + info[2] + "\"");
                parameters.add("\"serverid\":\"" + info[1] + "\"");
                if (info.length >= 6 && ("android".equalsIgnoreCase(info[5]) || "all".equalsIgnoreCase(info[5])
                        || "test".equalsIgnoreCase(info[5])))
                    parameters.add("\"servertype\":\"" + info[5] + "\"");
                else
                    parameters.add("\"servertype\":\"\"");
                parameters.add("\"product_id\":\"" + purchase.getSku() + "\"");
                parameters.add("\"payment_channal\":\"mob_google\"");
                String re = info[4];
                if (re != null && !TextUtils.isEmpty(re)) {
                    String[] rev = re.split("_");
                    parameters.add("\"cost\":\"" + (rev.length > 0 ? rev[0] : "") + "\"");
                    parameters.add("\"currency\":\"" + (rev.length > 1 ? rev[1] : "") + "\"");
                } else {
                    parameters.add("\"cost\":\"\"");
                    parameters.add("\"currency\":\"\"");
                }
                parameters.add("\"value\":\"\"");
                if (info.length >= 7)
                    parameters.add("\"oas_order_id\":\"" + info[6] + "\"");
                else
                    parameters.add("\"oas_order_id\":\"\"");
                parameters.add("\"third_party_orderid\":\"" + purchase.getOrderId() + "\"");
                parameters.add("\"result_code\":\"" + result.isSuccess() + "_" + verify + "\"");
                parameters.add("\"isreport\":\"" + (PhoneInfo.instance().isTrackAble() ? "Y" : "N") + "\"");

                List<String> status = new ArrayList<String>();
                status.add("\"event_type\":\"order\"");
                ReportUtils.add(ReportUtils.DEFAULTEVENT_PAID_MONEY, parameters, status);// ??Mdata
            } catch (Exception e) {
                BaseUtils.logError(TAG, "Google play billing send mdata fail.");
            }
            if (!verify) {
                Message msg = new Message();
                msg.what = 0;
                msg.obj = getResources()
                        .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_4"));
                myHandler.sendMessage(msg);
                BaseUtils.logError(TAG, "Error purchasing. Authenticity verification failed.");
                return;
            }

            BaseUtils.logDebug(TAG, "Purchase successful." + purchase.toString());

            checkAndAddPurchase(purchase);// catch???            

            check(purchase);

        }
    };

    /**
    * ????
    * @param p   ??
    * @return
    */
    public void checkAndAddPurchase(Purchase p) {
        try {
            long id = 0;
            if (GoogleBillingUtils.checkPurchaseIsExist(p)) {
                BaseUtils.logError(TAG, "????1");
            } else {
                id = GoogleBillingUtils.addPurchase(p);
                if (id > 0)
                    BaseUtils.logError(TAG, "????2");
                else
                    BaseUtils.logError(TAG, "???");
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    /**
     * ?
     * */
    private void consumeOldOrder(Purchase purchase, final int code, final int isEnd) {
        mHelper.consumeAsync(purchase, new IabHelper.OnConsumeFinishedListener() {
            public void onConsumeFinished(Purchase p, IabResult result) {
                BaseUtils.logDebug(TAG, "consumeOldOrder finished. Purchase: " + p + ", result: " + result);

                // if we were disposed of in the meantime, quit.
                if (mHelper == null)
                    return;

                Message msg = null;
                if (result.isSuccess()) {
                    BaseUtils.logDebug(TAG,
                            "consumeOldOrder successful. Provisioning. Purchase.orderID=" + p.getOrderId());
                    //                  case 1000000://???
                    //                case 1000002://?????2?

                    if (GoogleBillingUtils.deletePurchase(p.getOrderId()) > 0) {
                        if (code == 1000000 || code == 1000002) { // ????
                            msg = new Message();
                            msg.what = 103;//??
                            msg.obj = p;
                            myHandler.sendMessage(msg);

                            msg = new Message();
                            msg.what = 102;// 
                            msg.obj = p;
                            msg.arg1 = code;
                            myHandler.sendMessage(msg);
                        }
                    } else {
                        BaseUtils.logError(TAG, "delete by orderid=" + p.getOrderId());
                    }
                } else {
                    if (result.getResponse() == IabHelper.BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED) {
                        if (GoogleBillingUtils.deletePurchase(p.getOrderId()) > 0) {
                            //                      ???
                            //                     msg = new Message();
                            //                      msg.what = 102;// 
                            //                      msg.obj = p;
                            //                      myHandler.sendMessage(msg);
                        } else {
                            BaseUtils.logError(TAG, "delete by orderid=" + p.getOrderId());
                        }
                    }
                }

                myHandler.sendEmptyMessage(98);//??
            }
        });
    }

    private void consume(Purchase purchase, final int code) {
        mHelper.consumeAsync(purchase, new IabHelper.OnConsumeFinishedListener() {
            public void onConsumeFinished(Purchase p, IabResult result) {
                BaseUtils.logDebug(TAG, "Consumption finished. Purchase: " + p + ", result: " + result);

                // if we were disposed of in the meantime, quit.
                if (mHelper == null)
                    return;

                if (result.isFailure()) {
                    BaseUtils.logError(TAG,
                            "Error while consuming: " + IabHelper.getResponseDesc(result.getResponse()));
                    if (code == -1) {// ??
                        if (result.getResponse() == IabHelper.BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED) {// ? item not owned,??
                            //                         queryInventory();
                            myHandler.sendEmptyMessage(101);
                            return;
                        }
                        //????
                        Message msg = new Message();
                        msg.what = 0;
                        msg.obj = getResources()
                                .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_error_fail"));
                        myHandler.sendMessage(msg);
                        return;
                    }
                }

                if (result.isSuccess()) {
                    BaseUtils.logDebug(TAG,
                            "Consumption successful. Provisioning. Purchase.orderID=" + p.getOrderId());
                    //                  case 1000000://???
                    //                case 1000002://?????2?

                    if (GoogleBillingUtils.deletePurchase(p.getOrderId()) > 0) {// ??
                        if (code == 1000000 || code == 1000002) { // ????
                            Message msg = new Message();
                            msg = new Message();
                            msg.what = 102;// 
                            msg.obj = p;
                            msg.arg1 = code;
                            myHandler.sendMessage(msg);
                        }
                    } else {
                        BaseUtils.logError(TAG, "delete by orderid=" + p.getOrderId());
                    }
                }
                if (code == -1) {// ????
                    //                   launchPurchaseFlow();
                    //                   queryInventory();
                    if (isPageClose()) {
                        isPageCloseHandler();
                        return;
                    }
                    myHandler.sendEmptyMessage(101);
                    return;
                }
                Message msg = new Message();
                msg.what = HANDLER_SUCECCES;
                msg.arg1 = code;
                myHandler.sendMessage(msg);
                BaseUtils.logDebug(TAG, "End consumption flow.");
            }
        });
    }

    /**
     * ??
     */
    private void check(final Purchase purchase) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                Message msg = new Message();
                int res = -1;
                try {
                    res = HttpService.instance().checkPurchaseForGoogle(purchase, GoogleBillingUtils.SEPARATE);
                    switch (res) {
                    case 1000000://???
                    case 1000002://?????2?
                    case 1000006://?Google??
                    case 1000001://sign?????
                        BaseUtils.logDebug(TAG, "Code=" + res + "; Start consume." + purchase.toString());

                        msg.what = 100;
                        msg.arg1 = res;
                        msg.obj = purchase;
                        myHandler.sendMessage(msg);
                        break;

                    case 1000100://
                    case 1000004://ProductID?BUG
                        checkAndAddPurchase(purchase);
                        myHandler.sendEmptyMessage(HANDLER_FAIL);
                        break;

                    case 1000003://??-Google?
                    case 1000005://????
                    default:
                        msg.what = HANDLER_EXCEPTION;
                        msg.obj = purchase;
                        myHandler.sendMessage(msg);// retry
                        break;
                    }
                } catch (OasisSdkException e) {// oas?2???
                    msg.what = HANDLER_EXCEPTION;
                    msg.obj = purchase;
                    myHandler.sendMessage(msg);// retry
                } finally {
                    try {
                        String[] info = purchase.getDeveloperPayload().split(GoogleBillingUtils.SEPARATE);

                        // ?Mdata???
                        List<String> parameters = new ArrayList<String>();
                        parameters.add("\"uid\":\"" + info[0] + "\"");
                        parameters.add("\"roleid\":\"" + info[2] + "\"");
                        parameters.add("\"serverid\":\"" + info[1] + "\"");
                        if (info.length >= 6 && ("android".equalsIgnoreCase(info[5])
                                || "all".equalsIgnoreCase(info[5]) || "test".equalsIgnoreCase(info[5])))
                            parameters.add("\"servertype\":\"" + info[5] + "\"");
                        else
                            parameters.add("\"servertype\":\"\"");
                        parameters.add("\"product_id\":\"" + purchase.getSku() + "\"");
                        parameters.add("\"payment_channal\":\"mob_google\"");
                        String re = info[4];
                        if (re != null && !TextUtils.isEmpty(re)) {
                            String[] rev = re.split("_");
                            parameters.add("\"cost\":\"" + (rev.length > 0 ? rev[0] : "") + "\"");
                            parameters.add("\"currency\":\"" + (rev.length > 1 ? rev[1] : "") + "\"");
                        } else {
                            parameters.add("\"cost\":\"\"");
                            parameters.add("\"currency\":\"\"");
                        }
                        parameters.add("\"value\":\"\"");
                        if (info.length >= 7)
                            parameters.add("\"oas_order_id\":\"" + info[6] + "\"");
                        else
                            parameters.add("\"oas_order_id\":\"\"");
                        parameters.add("\"third_party_orderid\":\"" + purchase.getOrderId() + "\"");
                        parameters.add("\"result_code\":\"" + res + "\"");
                        parameters.add("\"isreport\":\"" + (PhoneInfo.instance().isTrackAble() ? "Y" : "N") + "\"");

                        List<String> status = new ArrayList<String>();
                        status.add("\"event_type\":\"order\"");
                        ReportUtils.add(ReportUtils.DEFAULTEVENT_ORDER_REPORTED, parameters, status);
                    } catch (Exception e) {
                        BaseUtils.logError(TAG, "Google play billing send mdata fail.");
                    }
                }
            }
        }).start();

        //       *          1000001:??key
        //       *          1000002:??
        //       *          1000003:??-Google?
        //       *          1000004ProductID?BUG
        //       *          1000005:????
        //       *          1000100:
    }

    public static class MyHandler extends Handler {

        // WeakReference to the outer class's instance.
        private WeakReference<GooglePlayBillingActivity> mOuter;

        public MyHandler(GooglePlayBillingActivity activity) {
            mOuter = new WeakReference<GooglePlayBillingActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {

            GooglePlayBillingActivity outer = mOuter.get();
            if (outer != null) {
                switch (msg.what) {
                case HANDLER_SUCECCES:
                    if (msg.arg1 == 1000000 || msg.arg1 == 1000002) {// ????
                        BaseUtils.showMsg(outer, outer.getResources().getString(
                                BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_error_success")));
                        outer.setResultInfo(OASISPlatformConstant.RESULT_SUCCESS, "????");
                    } else if (msg.arg1 == 1000006) {// ??Google?
                        BaseUtils.showMsg(outer, outer.getResources().getString(
                                BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_4")));
                        outer.setResultInfo(OASISPlatformConstant.RESULT_EXCEPTION,
                                "??Google?");
                    }
                    break;
                case HANDLER_FAIL:
                    BaseUtils.showMsg(outer, outer.getResources()
                            .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_error_fail")));
                    outer.setResultInfo(OASISPlatformConstant.RESULT_FAIL, "");

                    break;
                case HANDLER_EXCEPTION:
                    outer.setWaitScreen(false);
                    outer.checkAndAddPurchase((Purchase) msg.obj);
                    outer.alert((Purchase) msg.obj);
                    // ???
                    break;
                case 0:
                    outer.complain((String) msg.obj);
                    break;
                case 98:
                    outer.checkALLOrder(msg.arg1 + 1);
                    break;
                case 99:
                    outer.consumeOldOrder((Purchase) msg.obj, msg.arg1, msg.arg2);
                    break;
                case 100:
                    outer.checkAndAddPurchase((Purchase) msg.obj);
                    outer.consume((Purchase) msg.obj, msg.arg1);
                    break;
                case 101:
                    outer.queryInventory();
                    break;
                case 102:
                    Purchase p = (Purchase) msg.obj;
                    String[] info = p.getDeveloperPayload().split(GoogleBillingUtils.SEPARATE);
                    if (info != null && info.length >= 5 && !TextUtils.isEmpty(info[4])) {
                        String[] rev = info[4].split("_");// info[4]?2?9.999.99_RUB
                        double revenue = 0;
                        try {
                            revenue = Double.parseDouble(rev[0]);
                        } catch (Exception e) {
                            revenue = 0;
                        }

                        String currency = "";
                        if (rev.length > 1) {
                            currency = rev[1];
                        } else {
                            // ??
                            // info[4]????p.getSku????
                            if (SystemCache.payInfoLists != null)
                                for (PayInfoList payInfos : SystemCache.payInfoLists) {
                                    if ("mob_google".equals(payInfos.pay_way)) {
                                        for (PayInfoDetail detail : payInfos.list) {
                                            if (p.getSku().equals(detail.price_product_id)) {// sku? product id
                                                currency = detail.currency;
                                                break;
                                            }
                                        }
                                        break;
                                    }
                                } //end for
                        } //end else

                        if (revenue > 0 && !TextUtils.isEmpty(currency)) {// 0  ??Adjust
                            BaseUtils.trackRevenue(outer, ReportAdjustInfo.EVENTNAME_REVENUE + "_" + currency,
                                    revenue, currency, null);
                        }

                        // ?Mdata???
                        try {
                            List<String> parameters = new ArrayList<String>();
                            parameters.add("\"uid\":\"" + info[0] + "\"");
                            parameters.add("\"roleid\":\"" + info[2] + "\"");
                            parameters.add("\"serverid\":\"" + info[1] + "\"");
                            if (info.length >= 6 && ("android".equalsIgnoreCase(info[5])
                                    || "all".equalsIgnoreCase(info[5]) || "test".equalsIgnoreCase(info[5])))
                                parameters.add("\"servertype\":\"" + info[5] + "\"");
                            else
                                parameters.add("\"servertype\":\"" + SystemCache.userInfo.serverType + "\"");
                            parameters.add("\"product_id\":\"" + p.getSku() + "\"");
                            parameters.add("\"payment_channal\":\"mob_google\"");
                            parameters.add("\"cost\":\"" + revenue + "\"");
                            parameters.add("\"currency\":\"" + currency + "\"");
                            parameters.add("\"value\":\"\"");
                            if (info.length >= 7)
                                parameters.add("\"oas_order_id\":\"" + info[6] + "\"");
                            else
                                parameters.add("\"oas_order_id\":\"\"");

                            parameters.add("\"third_party_orderid\":\"" + p.getOrderId() + "\"");
                            parameters.add("\"result_code\":\"" + "" + msg.arg1 + "\"");
                            parameters.add(
                                    "\"isreport\":\"" + (PhoneInfo.instance().isTrackAble() ? "Y" : "N") + "\"");

                            List<String> status = new ArrayList<String>();
                            status.add("\"event_type\":\"paid\"");
                            status.add("\"isreport\":\"" + (PhoneInfo.instance().isTrackAble() ? "Y" : "N") + "\"");
                            ReportUtils.add(ReportUtils.DEFAULTEVENT_PAID, parameters, status);
                        } catch (Exception e) {
                            BaseUtils.logError(TAG, "Google play billing send mdata fail.");
                        }

                    }
                    break;
                case 103:
                    BaseUtils.showMsg(outer, outer.getResources()
                            .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_error_success")));
                    break;
                case -1:
                    outer.close();
                    break;
                case -2:
                    BaseUtils.showMsg(outer, (String) msg.obj);
                    break;
                case -10000:
                    outer.setWaitScreen(false);
                    switch (msg.arg1) {
                    case 1000000:
                        outer.setResultInfo(OASISPlatformConstant.RESULT_SUCCESS, "???");
                        outer.close();
                        break;
                    case 1000001:
                        outer.setResultInfo(OASISPlatformConstant.RESULT_FAIL, "sign?");
                        outer.close();
                        break;
                    case 1000002:
                        outer.setResultInfo(OASISPlatformConstant.RESULT_FAIL, "??");
                        outer.close();
                        break;
                    case 1000003:
                        outer.setResultInfo(OASISPlatformConstant.RESULT_FAIL, "product_id??");
                        outer.close();
                        break;
                    case 1000004://?sign?
                    case 1000005://???
                    case 1000006://?????1
                    case 1000007://???
                    case 1000008://??IP?
                    case 1000009://?? ??
                    case 1000010://?? ??
                    case 1000011://???
                        outer.setResultInfo(OASISPlatformConstant.RESULT_FAIL,
                                "????.Error:" + msg.arg1);
                        outer.close();
                        break;
                    case 1000100://
                        outer.setResultInfo(OASISPlatformConstant.RESULT_FAIL, "");
                        outer.close();
                        break;

                    default:
                        break;
                    }
                    break;
                default:

                    break;
                }
            }
        }
    }

    private void setResultInfo(int statusCode, String errorMessage) {
        if (SystemCache.oasisInterface != null)
            SystemCache.oasisInterface.paymentCallback("google", statusCode, errorMessage);
        else
            Log.e(TAG, "OASISPlatformInterface ?paymentCallback");
        close();
    }

    @Override
    protected void onResume() {
        super.onResume();

    }

    // We're being destroyed. It's important to dispose of the helper here!
    @Override
    public void onDestroy() {
        super.onDestroy();

        // very important:
        BaseUtils.logDebug(TAG, "Destroying helper.");
        if (mHelper != null) {
            try {
                mHelper.dispose();
            } catch (Exception e) {
                BaseUtils.logError(TAG, "Google onDestroy() exception:" + e.getMessage());
            }
            mHelper = null;
        }
    }

    void complain(String message) {
        BaseUtils.logError(TAG, "**** TrivialDrive Error: " + message);
        //        alert(message);
        BaseUtils.showMsg(this.getApplicationContext(), message);
        close();
    }

    void close() {
        setWaitScreen(false);
        finish();
    }

    /**
     * ??????
     * @param purchase
     */
    void alert(final Purchase purchase) {
        final AlertDialog d = new AlertDialog.Builder(this).create();
        d.show();
        d.setContentView(BaseUtils.getResourceValue("layout", "oasisgames_sdk_common_dialog_notitle"));
        d.setCanceledOnTouchOutside(false);
        d.setCancelable(false);
        TextView retry = (TextView) d
                .findViewById(BaseUtils.getResourceValue("id", "oasisgames_sdk_common_dialog_notitle_sure"));
        retry.setText(getResources()
                .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_alert_retry")));
        retry.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // ?
                d.dismiss();
                setWaitScreen(true);
                check(purchase);
            }
        });
        TextView close = (TextView) d
                .findViewById(BaseUtils.getResourceValue("id", "oasisgames_sdk_common_dialog_notitle_cancle"));
        close.setText(getResources()
                .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_alert_close")));
        close.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                d.dismiss();
                setResultInfo(OASISPlatformConstant.RESULT_EXCEPTION_GOOGLEPAY_EXCEPTION,
                        "?????");
                close();
            }
        });

        TextView content = (TextView) d
                .findViewById(BaseUtils.getResourceValue("id", "oasisgames_sdk_common_dialog_notitle_content"));
        content.setText(getResources()
                .getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_alert_content")));

    }

    /**
     * ??????
     */
    private void isPageCloseHandler() {
        myHandler.sendEmptyMessage(-1);
        setResultInfo(OASISPlatformConstant.RESULT_CANCLE, "??");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        return true;
    }

    private void initSandBox() {
        findViewById(BaseUtils.getResourceValue("id", "oasisgames_sdk_pay_google_sandbox"))
                .setVisibility(View.VISIBLE);
        findViewById(BaseUtils.getResourceValue("id", "oasisgames_sdk_pay_google_sandbox_close"))
                .setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        setResultInfo(OASISPlatformConstant.RESULT_CANCLE, "??");
                        close();
                    }
                });
        ((TextView) findViewById(BaseUtils.getResourceValue("id", "oasisgames_sdk_pay_google_sandbox_content")))
                .setText(getString(BaseUtils.getResourceValue("string", "oasisgames_sdk_sandbox_google_notice1"))
                        + "Google Play");
        findViewById(BaseUtils.getResourceValue("id", "oasisgames_sdk_pay_google_sandbox_pay_success"))
                .setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        //?
                        setWaitScreen(true);
                        new Thread(new Runnable() {

                            @Override
                            public void run() {
                                int res = 0;
                                Purchase p = new Purchase(productID, "");
                                try {
                                    res = HttpService.instance().checkPurchaseForGoogleBySandBox(p);
                                } catch (OasisSdkException e) {
                                    res = 1000100;
                                }
                                Message msg = new Message();
                                msg.what = -10000;
                                msg.arg1 = res;
                                myHandler.sendMessage(msg);
                            }
                        }).start();
                    }
                });
        findViewById(BaseUtils.getResourceValue("id", "oasisgames_sdk_pay_google_sandbox_pay_fail"))
                .setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        BaseUtils.showMsg(GooglePlayBillingActivity.this.getApplicationContext(), getString(
                                BaseUtils.getResourceValue("string", "oasisgames_sdk_pay_google_notice_3")));
                        setResultInfo(OASISPlatformConstant.RESULT_FAIL, "");
                        close();
                    }
                });

        setWaitScreen(false);
    }
}