4

Ok so I have been trying to fix this for days, and I'm not coming here looking for someone to do my work for me as I have been troubleshooting and fixed every single error message in the LogCat. I am developing an Android game using Andengine (this might be part of the problem so being familiar with it could help). I'm not doing anything too fancy, my game activities are all single scene and don't have any Physics or anything like that, just a bunch of sprites and textures. I also used Andengine for all of the other activities in my game because I find it to be a very easy way to set up graphically appealing screens. One such screen is my in-app store, where users can buy levelpacks and new sprites. The billing part of this all works great, the purchases go through to the Market and there's nothing too complicated there...

When the user clicks buy, the market screen pops up and loads the product they have selected (these are real products, not the android tests although the game is not published). The Market screen pops up over the current activity, regardless of whether I use the "Android 2.0" implementation where it is part of the game's stack or I use the "Android 1.6" implementation and it is part of its own stack. I would prefer to use the Android 2.0 implementation but if I can only get the 1.6 to work I will take that. So anyway, the problem arises when the user either cancels the purchase using the back button or completes the purchase with a credit card, both result in the market screen disappearing and the app starting a new activity that is just a black screen (which eventually times out and causes a force close). The purchase goes through OK but the user does not get the product because the game force quits before we get to the code to change the user's items in the game. Now for some code, I used this tutorial (http://www.anddev.org/advanced-tutorials-f21/simple-inapp-billing-payment-t52060.html) without changing much of anything. The BillingHelper class is most important, as it holds the requestPurchase() method and the startBuyPageActivity() methods. I call request purchase from my StoreFront activity like this:

            BillingHelper.requestPurchase(StoreFront.this, itemID); 

and in the onCreate of the StoreFront I have this stuff (as told to do by the tut):

        startService(new Intent(mContext, BillingService.class));
    BillingHelper.setCompletedHandler(mTransactionHandler);

...

//some handler that billing needs
public Handler mTransactionHandler = new Handler(){
    public void handleMessage(android.os.Message msg) {
        Log.i(TAG, "Transaction complete");
        Log.i(TAG, "Transaction status: "+BillingHelper.latestPurchase.purchaseState);
        Log.i(TAG, "Item purchased is: "+BillingHelper.latestPurchase.productId);

        if(BillingHelper.latestPurchase.isPurchased()){
            //TODO do something here if we've completed our latest purchase,
            //this should be with the status bar notifications and
            //saved preferences
        }
    };

};

So I don't think the problem lies there. Here are the relevant parts of BillingHelper

protected static void requestPurchase(Context activityContext, String itemId){
    if (amIDead()) {
        return;
    }
    Log.i(TAG, "requestPurchase()");
    Bundle request = makeRequestBundle("REQUEST_PURCHASE");
    request.putString("ITEM_ID", itemId);
    try {
        Bundle response = mService.sendBillingRequest(request);

        //The RESPONSE_CODE key provides you with the status of the request
        Integer responseCodeIndex   = (Integer) response.get("RESPONSE_CODE");
        //The PURCHASE_INTENT key provides you with a PendingIntent, which you can use to launch the checkout UI
        PendingIntent pendingIntent = (PendingIntent) response.get("PURCHASE_INTENT");
        //The REQUEST_ID key provides you with a unique request identifier for the request
        Long requestIndentifier     = (Long) response.get("REQUEST_ID");
        Log.i(TAG, "current request is:" + requestIndentifier);
        C.ResponseCode responseCode = C.ResponseCode.valueOf(responseCodeIndex);
        Log.i(TAG, "REQUEST_PURCHASE Sync Response code: "+responseCode.toString());

        startBuyPageActivity(pendingIntent, new Intent(), activityContext);
    } catch (RemoteException e) {
        Log.e(TAG, "Failed, internet error maybe", e);
        Log.e(TAG, "Billing supported: "+isBillingSupported());
    }
}

Which I have tried calling from StoreFront with a variety of arguments as "ActivityContext" such as StoreFront.this, getApplicationContext(), a static context store elsewhere, a static Activity stored elsewhere, getBaseContext() anything I could possible think of...

Here is the other relevant activity

private static void startBuyPageActivity(PendingIntent pendingIntent, Intent intent, Context context){
    //android 1.6 method
    try {
        pendingIntent.send(context, 0, intent);         
    } catch (CanceledException e){
        Log.e(TAG, "startBuyPageActivity CanceledException");
    }
}

Nothing fancy, I just want the user to be returned to any of my various activities (preferably StoreFront) when they either buy the item or press back during the process. HELP PLEASE!

Edit: I want any possible solution to allow in-app billing to return to my app after the purchase is complete, even the messiest solution.

EDIT

A logcat and method calls of what the issue:

  "BillingService Starting", 
  BillingHelper.setCompletedHandler(), 
  StoreFront.onStart() called, 
  StoreFront.onResume() called, 
  "BillingService Service starting with onCreate", 
  "BillingService Market Billing Service Successfully Bound", 
  "BillingService Market Billing Service Connected", 
  BillingHelper.instantiateHelper(), 
  then this is where I actually click the buy button in the store (all of that runs just when opening StoreFront):
  BillingHelper.setCompletedHandler(), 
  BillingHelper.isBillingSupported(), 
  BillingHelper.amIDead(), 
  BillingHelper.makeRequestBundle(), 
  "BillingService isBillingSupported response was: RESULT OK", 
  BillingHelper.requestPurchase(), 
  BillingHelper.amIDead(), 
  "BillingService requestPurchase()", 
  BillingHelper.makeRequestBundle(), 
  "BillingService current request is ......", 
  "BillingService REQUEST PURCHASE Sync Response code: RESULT OK", 
  BillingHelper.startBuyPageActivity(), 
  "BillingService Recieved action: com.android.vending.billing.RESPONSE CODE", 
  "BillingService checkResponseCode got requestID..."
  "BillingService checkResponseCode go responseCode RESULT ERROR" 
  (this is because I can't purchase on this device), 
  and then I get an Error message saying: "E 32427 Surface surface (identity=5925) is invalid, err=-19 (No such device)" and from there nothing works anymore. 

Also I have tested this on a different phone (another developer I am working with, who can actually buy things in it but still gets the black screen error) and he never got the Handler messages you mentioned in your comment either

Edit: if I had to guess where the error is, I'd say it's this

06-16 11:20:23.635: DEBUG/dalvikvm(3807): GC_EXPLICIT freed 53K, 45% free 3710K/6663K, external 1K/513K, paused 102ms
06-16 11:20:23.885: ERROR/Surface(3807): surface (identity=158) is invalid, err=-19 (No such device)
06-16 11:20:23.905: ERROR/Surface(3807): surface (identity=158) is invalid, err=-19 (No such device)
06-16 11:20:23.905: ERROR/Surface(3807): surface (identity=158) is invalid, err=-19 (No such device)
06-16 11:20:23.905: ERROR/Adreno200-EGL(3807): egliSwapWindowSurface: unable to dequeue native buffer

Note that the interrupted exception is expected by the Andengine library so that is a red herring.

Also (I hope this is allowed on here) I will offer paypal reward for a solution. If this is against the Terms of SO then just delete this line, please don't close this question.

Sam Stern
  • 24,624
  • 13
  • 93
  • 124
  • 1
    Are you getting "Transaction complete" and "Item purchased is: " back from your handler? i.e. is the handler being called – Blundell Jun 15 '11 at 20:59
  • No I actually am not, now that you mention it. The purchase is definitely going through and being charged because it comes up in my merchant account but I'm not seeing it in the LogCat. Does this mean you know what the problem is (if so you'd be my personal savior). – Sam Stern Jun 15 '11 at 22:54
  • 1
    What are you getting out of your LogCat, the InApp tut has a lot of Log out so your logcat may be able to show where it's stopped. Have a look at the verifyPurchase(string, string) method in BillingHelper.java this is likely where your up to – Blundell Jun 16 '11 at 07:58
  • Ok so I can't actually complete the purchase on my own phone (something about buying your own products makes it fail) but it should just simulate any other user getting an error so it still shouldn't go black like it does. Here is what happens when I open my store (based on Log messages I added to every method): – Sam Stern Jun 16 '11 at 12:03
  • BillingHelper.setCompletedHandler(), BillingHelper.isBillingSupported(), BillingHelper.amIDead(), BillingHelper.makeRequestBundle(), "BillingService isBillingSupported response was: RESULT OK", BillingHelper.requestPurchase(), BillingHelper.amIDead(), "BillingService requestPurchase()", BillingHelper.makeRequestBundle(), "BillingService current request is ......", "BillingService REQUEST PURCHASE Sync Response code: RESULT OK", BillingHelper.startBuyPageActivity(), "BillingService Recieved action: com.android.vending.billing.RESPONSE CODE", "BillingService checkResponseCode got requestID..." – Sam Stern Jun 16 '11 at 12:13
  • 1
    Don't write stuff like that in a comment. Just edit your question and put **EDIT** at the bottom. Reading through it now – Blundell Jun 16 '11 at 12:36
  • 1
    From what I can gather it looks like you've just got some general billing error. Can you check these general issues: http://stackoverflow.com/questions/5501370/error-testing-in-app-billing-sample-dungeons/5501526#5501526 – Blundell Jun 16 '11 at 13:07
  • What I gave you was the LogCat from my phone, which always returns a billing error because it is my own account (Google really makes it rough for solo devs) but on a friend's phone the purchase goes through successfully and is billed, it is after the purchase action is completed (by either succeeding or canceling) that my app goes to the black screen and eventually times out. – Sam Stern Jun 16 '11 at 13:25
  • 1
    Have you got a dev phone? You could always use http://www.perfectomobile.com/ they give you an hour free. Would really help to have the logcat of a successful purchase to see where it get's up to, then we can figure out why it isn't calling the handler. – Blundell Jun 16 '11 at 13:31
  • Ok I can get that today, some time this afternoon hopefully. I'll have a friend run it and post his entire logcat as an answer here or something like that. Really thank you so much for even trying to help, I appreciate it a lot. – Sam Stern Jun 16 '11 at 13:54

1 Answers1

5

I may know what's wrong and I have a test for you to do. The buy screen runs a finish call after the user cancels the purchase or completes the purchase. For me for some reason the finish call was drifting down into the currently running activity and (CLOSING??? it).

Here's the relevant line from the log:

06-16 11:20:22.774: WARN/ActivityManager(132): Duplicate finish request for HistoryRecord{40ace828 com.android.vending/.billing.InAppBuyPageActivity}

I think I fixed this in my code problem is that I can't remember exactly what I did (maybe didn't call finish in my purchase complete handler...)

I don't know anything about Andgen, but what would happen if a finish call got called on the main Andgen activity? I'd imagine it would stop execution and you might get a black screen and an app crash.

So to test this, create a separate activity for you buy page. Doesn't need to be complicated - maybe have it just buy one canned product after it starts up. Run your code and see if it still gives you the black screen of doom. My bet: it may exit out of the activity back to your game but I think it'll work.

Hope this helps and Good Luck!

walta
  • 3,466
  • 22
  • 24
  • 2
    You are my personal hero. The bounty is all you and my many many thanks. – Sam Stern Jun 20 '11 at 05:00
  • Was having a similar issue, after creating a new activity and doing the purchasing from there then returning back to my andengine activity after the purchase everything now works :D – Spider Mar 21 '13 at 01:41