Fix to Double Star, Level 6

The latest update of Double Star fixes Level 6. For fun, for those of you who already finished that level, you might want to go back and try again. You can get to some of the alien starships, but not all of them. So you have that to figure out. And watch out if the tractor beam gets you and pulls you into the the cluster of alien ships. Certain death awaits.


Posted in Android, Double Star | Leave a comment

Android Example of a Zoomable Game Board

In this article, I briefly describe how I built a simple game board in Android. The sample app shows a grid of squares that represents a game board. The squares on the game board come from an array of image tiles. The grid can be zoomed in or out and moved. Touch events are triggered when squares are touched. Regular and long press are handled. With this sample as a starting point, it should be easy to build a game that uses a board of squares.

The video below shows the demo app in action.

Source Code

Full source code for this game board demo is available at the download page.

Classes in the Demo Application

There are four classes that do most of the work in this sample application.

This view supports both zooming and panning and other touch gestures and actions. What gets shown on the screen depends on the onDraw method provided by its subclasses. In this demo app, the subclass is GameBoardView.

This view displays a grid of rectangles that can be zoomed in and out and panned. The default grid is 13 x 13, with 8 squares showing. The zoom point is the center of the view.

Defines the listener interface for touch actions on a GameBoardView. It defines onTouchDown, onTouchUp, and onLongTouchUp. For onTouchUp and onLongTouchUp, the listener receives index numbers of the squares of the grid. No coordinates are included in the call to onTouchDown.

This is the class that brings together all the other classes into a working demo. It generates a random grid of of squares. The grid represents a simple game board. Each of the squares shows a white, red, or blue tile. This activity connects a GameBoardView to the game board grid so it can be displayed on the screen. This activity also defines actions for touch actions. When a square is touched, it is highlighted to show that it is selected. When a long touch is done, the square changes to the next color in the sequence (white, red, blue).

How It Works

GameBoardActivity has a simple layout. A real game would have much more, but all I wanted to show was how easily a GameBoardView could be used to fill up the screen with a grid of squares, even if there were more squares than fit on the screen. The layout says to fill the screen width with a game board and to fill whatever is left of the height after the simple text instructions are displayed.

 android:orientation="vertical" >


 android:text="@string/instructions" />


The connection to the GameBoardView is made in onCreate. The activity provides the initial grid values to the view and attaches itself as the listener for touch events.

@Override public void onCreate(Bundle savedInstanceState) {

 setupMyGrid (NumSquaresOnGridSide);
 GameBoardView gv = (GameBoardView) findViewById (;
 if (gv != null) {
  setGridView (gv);

  gv.setNumSquaresAlongCanvas (NumSquaresOnGridSide);
  gv.setNumSquaresAlongSide (NumSquaresOnViewSide);
  gv.updateGrid (getGrid ());
  gv.setTouchListener (this);

The grid is generated randomly with values between 0 and 2. Those values are used by GameBoardView to look up images from its array of three images.

The touch listener methods in GameBoardActivity are there to illustrate how to select squares and take actions on the game board. The onTouchUp method shows how a square is selected. It does not update the grid value because selection state can be maintained in the GameBoardView. In a real game, other actions, such as button presses, might want to know which square is selected.

public void onTouchUp (int downX, int downY, int upX, int upY) {
 GameBoardView gv = getGridView ();
 if (gv == null) return;

 boolean isSelected = gv.isSelected (upX, upY);
 gv.clearSelections ();
 if (!isSelected) gv.toggleSelection (upX, upY);
 gv.invalidate ();


The long press handling is a bit different. It results in the value on the grid being changed. After a change to the board, the view is informed that it needs to redraw itself. This happens in this demo in response to a long press, but in a real game, it’s more likely going to be that some computations have modified the grid contents and it’s time to update the display.

public void onLongTouchUp (int downX, int downY, int upX, int upY) {
 GameBoardView gv = getGridView ();
 if (gv == null) return;

 int oldValue = gv.gridValue (upX, upY);
 int newValue = oldValue + 1;
 if (newValue >= NumRedBlueTypes) newValue = 0;
 gv.setGridValue (upX, upY, newValue);
 gv.invalidate ();


Next we will examine how a GameBoardView works. Its two main responsibilities are: (1) drawing the images squares onto the screen as an x-y grid; (2) handling touch events and converting the view coordinates of the touch points into the index values between 1 and the number of squares along the side of the grid.

The most complicated thing the view has to do is be able to draw all the squares of the grid on the screen, even if they do not all fit in the height and width allocated for the view. It writes onto a canvas that is just large enough to hold all the squares on the grid. The figure below depicts roughly what is going on.


The size of the canvas object is determined by the size of a square. The square size is determined by how many squares fit along the shortest edge of the view. In this demo program, the activity requests for there to be 13 squares along the edge of the grid and for there to be 8 squares visible in the view. So the canvas size is roughly 1.6 times the view size. (13 / 8 = 1.625).

The view supports panning and zooming, but most of the work for that is done in class PanZoomView. Think of it this way. Panning means the green canvas box moves around, left and right, and up and down. The user sees what is in the gray zone. Zooming means that the green canvas box gets larger and smaller, revealing different parts of the canvas in the gray box.

The images that are drawn on the screen are defined in an array in GameBoardView. There is one set of images for the regular images and another set for when a square is selected. As you read through the code, you will see the place in getBitmapsArray where the bitmap objects are set up from the resource ids. Doing this once speeds up the drawing operation.

static private final int [] mUnselectedImageIds
 = {R.drawable.no_marker_default,
static private final int [] mSelectedImageIds
 = {R.drawable.no_marker_highlighted,
private Bitmap [] mBitmaps;
private Bitmap [] mSelectedBitmaps;

Drawing is done in the onDrawPz method and drawOnCanvas methods. The onDrawPz method is what the superclass (PanZoomView) put in place for subclasses to draw their contents.  There is a lot going on in that method, but basically all it is doing is (1) figuring out the square size from the view size; (2) figuring out how large the canvas is and where its origin point; (3) looping through the grid values and displaying the right image in each square. Parts 1-2 are done in onDrawPz. It looks a bit like this:

@Override public void onDrawPz(Canvas canvas) {;

 ... setting a lot of variables ...
 // The canvas is translated by the amount we have
 // scrolled and the standard amount to move the origin
 // of the canvas up and left so the region is centered
 // in the view. (Note: mPosX/mPosY are defined in PanZoomView.)
 float x = 0, y = 0;
 mPosX0 = mOriginOffsetX;
 mPosY0 = mOriginOffsetY;
 x = mPosX - mPosX0;
 y = mPosY - mPosY0;
 canvas.translate (x, y);

 ... more set up ...

 // The focus point for zooming is the center of the
 // displayable region. That point is defined by half
 // the canvas width and height.
 mFocusX = mHalfMaxCanvasWidth;
 mFocusY = mHalfMaxCanvasHeight;
 canvas.scale (mScaleFactor, mScaleFactor, mFocusX, mFocusY);

 ... more ...
 // Do the drawing operation for the view.
 drawOnCanvas (canvas);

It is a bit more involved than that because it has to account for the fact that code in its superclass is tracking touches and supporting pan and zoom gestures. So that’s why you see calls like “canvas.translate” and “canvas.scale”.

With all of that set up there in onDrawPz, the drawOnCanvas method is actually pretty easy to understand. It is going to draw the 13 x 13 grid on the canvas. It looks up values from the grid object, which specifies the index number of what image to put on the screen. It then has two loops where each of the images is drawn onto the canvas.

public void drawOnCanvas (Canvas canvas) {
 int x, y;
 float fx, fy;
 Paint paint = new Paint();
 Bitmap [] bitmaps = getBitmapsArray ();
 Bitmap [] selectedBitmaps = mSelectedBitmaps;
 int [] [] grid = getGridArray ();
 // Set width and height for the rectangle to be drawn.
 RectF dest1 = mDestRectF;
 // Draw squares to fill the grid.
 float dx = 0, dy = 0;
 for (int j = 0; j < pNumSquaresAlongCanvas; j++) {
 dx = 0;
 for (int i = 0; i < pNumSquaresAlongCanvas; i++) {
   int bindex = grid [j][i];
   boolean isSelected = (mGridSelect [j][i] > 0);

   Bitmap b1 = isSelected ? selectedBitmaps [bindex]
                          : bitmaps [bindex];
   dest1.offsetTo (dx, dy);
   canvas.drawBitmap (b1, null, dest1, paint);
   dx = dx + mSquareWidth;
 dy = dy + mSquareHeight;

Touches are tracked in PanZoomView. All GameBoardView has to do is convert touches in the View coordinate system that PanZoomView supports into the x-y grid coordinates that GameBoardView listener objects expect. Here is an excerpt from the onTouchUp method.

public void onTouchUp (float downX, float downY, 
                       float upX, float upY) {

 long nDownTime = mDownTime;
 mDownTime = 0l;

 // Figure out if this was a long press.
 long nUpTime = System.nanoTime ();
 boolean isLongPress = (nUpTime - nDownTime) > mLongPressTimeOut;

 // Convert view coordinates to canvas coordinates
 // and, eventually to index values for the grid cells.

 // We want integer index values to call the listener.
 int sUpX = (int) Math.floor (fx2) + 1;
 int sUpY = (int) Math.floor (fy2) + 1;
 int sDownX = (int) Math.floor (dfx2) + 1;
 int sDownY = (int) Math.floor (dfy2) + 1;

 // Next check to see if there is a listener for these events.
 // If there is not, there is nothing else to do.
 GameBoardTouchListener listener = getTouchListener ();
 if (listener == null) return;

 // Tell the listener about the Up event. 
 if (isLongPress)
 listener.onLongTouchUp (sDownX, sDownY, sUpX, sUpY); 
 else listener.onTouchUp (sDownX, sDownY, sUpX, sUpY); 

A very important class in this sample app is PanZoomView. It handles all the low level things related to touch, pan, and zoom gestures. I won’t go into the details here, but you should spend some time reading through it so you understand its onTouchEvent method and its ScaleGestureDetector object. You will also see how it translates all of the touches into method calls (as with onTouchUp and onTouchDown) or changes in instance variables for panning and zooming.

PanZoomView is a class that you might be able to reuse in different contexts. Just override its assorted “supportsXXX” methods (e.g. supportsPan, supportsZoom) and implement your own onDrawPz method for new subclasses.

Game Board In Action

This code is a good starting point for a game. I have used it in my Gomoku game: Gomoku League on Google Play. That game can be played on an 11×11 board or a 19×19 board. For the larger board, the zooming and panning features are very useful.

Another game app that uses the PanZoomView and has its own variation of a GameBoardView is my Double Star game. It is in beta test. Go the Double Star page on Google Play and click “Become a Tester”.


I have experimented with panning and zooming and displaying grids in several different demo applications.

  • Android Rotate and Scale Bitmaps  (February, 2014) – This tutorial app covers scaling of bitmaps, rotation of bitmaps, and translation from one origin to another.
Posted in Android, Game Design | Tagged , , , , , , | Leave a comment

Demo of a Zoomable Game Board

For my next Android tutorial, I am working on a demo app for a game board.  The app displays a grid of squares that represents a game board. The grid can be zoomed in or out and moved. Touch events are triggered when squares are touched. Regular and long press are handled.

Here is a short video of the demo app in action. This was recorded with the “Show Touches” option on in Android Settings. So the small white circles that appear are the touch points.

The source code and a write up for this demo will be available here on this blog in the next week or two. (Update – here is the link: Android Example of a Zoomable Game Board.)

If you are interested in how I made the demo video, see my earlier blog note: Making Promo Videos for Your Android App.

Posted in Android, Game Design | Tagged , , , , , | Leave a comment

Saving Game Progress in the Cloud in Double Star

Double Star is a turn-based space war game for Android. The most recent version of the app now supports saving game progress in the cloud.  This gives players: (a) game play across multiple devices; and (b) restoring progress after reinstallation.

blog-saved-games2In Double Star, you are not required to sign in with Google to play. Both offline and online play are supported.

To try the game, go to the Double Star page on Google Play and click “Become a Tester”. Doing that will take you to the Google Play store and allow you to install the app.


Posted in Android | Tagged , , , | Leave a comment

Method Overriding in C# and Java

Recently I have been trying to learn C#. As a long-time Java developer, there have been a few surprises. C# and Java have a lot in common, so it’s hard for me to notice some of the subtle differences. Today, for instance, I found out that method overriding in C# takes extra effort. In Java, you define methods and then override them in subclasses by simply declaring a method with the same name and arguments. That is not the case in C#, but it took me a while to figure out why the Java code I was converting to C# was not working correctly.

With C#, you have to add the “virtual” keyword to any method you intend to override. In subclasses, you have to add the “override” keyword. This is illustrated below for a “makeMove” method for the game of Gomoku.

public class GomokuPlayer

public virtual Move makeMove (State gstate, int whichPlayer) {
    return someMove;
public class FastPlayer : GomokuPlayer {
 public override Move makeMove (State gstate, int whichPlayer) {
    return myMove;

C# virtual and override are well explained here:

Posted in Java | Tagged , | 1 Comment

Atari: Game Over

I just watched “Atari: Game Over”. It is a fun documentary about Atari, the old video game company from the 80’s. Interesting  to hear from some of the designers of the early video games. See

It is available on Showtime, some Microsoft site, and probably a few other places.

Posted in Game Design | Leave a comment

Tutorial: How to Implement In-app Billing in Android – Part 2

Part 1 of this article was my guide on how to get started with in-app purchases in Android. It was published in July 2014. Finally, here is part 2.

Part 1 covered the operational side of things: defining in-app products, application keys, etc. In this article, I will offer some suggestions on how to adapt the TrivialDrive code for your own app. The code provided with TrivialDrive is very well structured and we all can learn a lot from it. Most of the hard work is done in classes inside the util package of TrivialDrive. Without that package, the MainActivity would be much more difficult. The changes I suggest below are refinements on what is in the MainActivity provided by the Google team.

For my own work, I made the transition from the in-app purchases of the TrivialDrive sample app (Figure 1, left) to the purchases of my space war app (Figure 2, right).



Adapting the Code for Your Own App

In this section, I will describe how I have adapted the code to an app I am working on. I will use the TrivialDrive app code to illustrate what I did, rather than using code from my space war app. The advantage of that is that I can provide the source code of a completely working app for you to try out and work with. If you want to have that code installed while you work, download the source code from here: zip file of finished sample for part 2.

Assuming you have gone through Part 1, you have a working copy of the TrivialDrive app. Make a copy of the whole app and make sure the copy compiles cleanly. Check the project preferences and be sure you are using a new version of Android (5 or higher).

The sample code that I provide starts with a package name of “com.wglxy.example.trivialdrive2”. Rename the project package. You need to do this because every app that gets published must have a unique package name. Then go into the AndroidManifest.xml file and change the package there too. You will also have to fix the line in MainActivity that imports the R class. Change that line so it gets R from your new package. (Note: the screenshots I include below are from Eclipse. I have not yet switched over to Android Studio.)


I restructured the code in anticipation of building an app that might have more than one activity that deals with in-app products. I added several extra classes. One is a Constants class and another is a superclass (IabActivity) where I put code needed by all of the activities that do in-app billing transactions.

Constants are in a file. The values are the id strings that you define in the Google Play Developer Console, in the section for in-app products. The values for this demo app are shown below. For your own app, you would add constants for your own set of products.

// In-app billing constants

// SKUs for our products: the premium upgrade (non-consumable)
// and gas (consumable)
public static final String SKU_PREMIUM = "premium2";
public static final String SKU_GAS = "gas2";

// SKU for our subscription (infinite gas)
public static final String SKU_INFINITE_GAS = "infinite_gas2";

Class IabActivity is a new class I added. I added it so I would have one place for the new code I added to support in-app billing. Because IAB code makes requests asynchronously, it is fairly complicated. If your app has only a single activity or you have only one activity where all in-app purchases are made, you won’t necessarily need a superclass.  I chose to add a subclass to reduce the amount of duplicate code in the subclasses. (That’s what I meant when I said earlier that my changes are a refinement of the original code.)

IabActivity bridges the gap between the generic, reusable code provided in the trivialdrive2.util package. IabActivity holds constants, variables, and methods that are specific to the application.

Let’s have a look at the different sections of the IabActivity class.

Variables Section of IabActivity

// Does the user have the premium upgrade?
 protected boolean mIsPremium = false;

// Does the user have an active subscription to the 
// infinite gas plan?
 protected boolean mSubscribedToInfiniteGas = false;

These variables indicate which items have been purchased. In TrivialDrive, you can upgrade your car to use premium gas. Another one of the purchases you can make is a subscription for unlimited gas. The regular gas that you purchase is a consumable item. That means that its purchase affects the state of the app as soon as the purchase  goes through. The state variables related to regular gas are in MainActivity.

Listeners section of IabActivity

A lot of work gets done inside the IabHelper class in the util package of TrivialDrive. For that to work, we need some Listener objects.

 * mGotInventoryListener - Listener that's called when we finish 
 * querying the items and subscriptions we own.
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = 
   new IabHelper.QueryInventoryFinishedListener() {
      public void onQueryInventoryFinished
                   (IabResult result, Inventory inventory) {
 * mConsumeFinishedListener - Listener that's called when 
 * consumption of the purchase item finishes
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = 
   new IabHelper.OnConsumeFinishedListener() {
      public void onConsumeFinished
                     (Purchase purchase, IabResult result) {
 * mPurchaseFinishedListener - Listener that's called when a 
 * purchase is finished
   mPurchaseFinishedListener = 
      new IabHelper.OnIabPurchaseFinishedListener() {
         public void onIabPurchaseFinished 
                       (IabResult result, Purchase purchase) {

Most of the work associated with an in-app purchase is done by code in the util package. Asynchronous calls are made there. The listeners defined in the Listeners section define the callback methods for those calls. I will say more about these listeners below.

IabHelper variable in IabActivity

  * This variable holds the value of an IabHelper object.
private IabHelper pIabHelper;

The most important class in the TrivialDrive util package is IabHelper. As stated in its comment section, IabHelper “provides convenience methods for inapp billing. You can create one instance of this class for your application and use it to process inapp billing operations”. You will see how that is done below.

Methods section of IabActivity

There are quite a few methods in the IabActivity superclass. Some of them are there to support the activity lifecycle and to make in-app purchases. Others are just there for convenience. Subclasses can make use of them and the Listener methods use them too.

// Methods for the Activity lifecycle
@Override protected void onActivityResult 
             (int requestCode, int resultCode, Intent data);
@Override protected void onCreate(Bundle savedInstanceState);
@Override public void onDestroy ();

// Methods for in-app purchases
protected void launchInAppPurchaseFlow 
                 (Activity a, String sku);
protected void launchSubscriptionPurchaseFlow 
                 (Activity a, String sku);
protected void launchInAppPurchaseFlow 
                 (Activity a, String sku, String itemType);
void onIabPurchaseFailed (IabHelper h, int errorNum);
boolean verifyDeveloperPayload(Purchase p);
protected void setupIabHelper 
                (final boolean showListedSkus, 
                 final boolean showErrors);
// Methods to help with setup and consuming items. 
void onIabConsumeItemFailed (IabHelper h);
void onIabConsumeItemSucceeded 
       (IabHelper h, Purchase purchase, IabResult result);
void onIabSetupFailed (IabHelper h);
void onIabSetupSucceeded 
       (IabHelper h, IabResult result, Inventory inventory);
// Miscellaneous methods
protected void alert(String message);
protected void complain(String message);
public void toast (int stringId);
public void toast (String msg);

Rather than explain all of these on their own, let’s take a look at the MainActivity class and see how these superclass methods are used.

Handling Purchases in MainActivity

In the TrivialDrive sample app, there is a single class, MainActivity, which uses in-app billing code. It can serve as a model for how purchases can be done in an app.

A purchase in TrvialDrive starts when the user touches one of the purchase buttons. The three buttons are “Buy Gas”, “Upgrade My Car”, and “Get Infinite Gas”. They are shown in the figure below. For those buttons to work, there is a fair amount of set up work that has to be done. There is code to handle the button clicks and to react to the asynchronous calls, which are made by the IabHelper class in the util package and by the IabActivity class.


When the user touches a button, like the “Buy Gas” button, a call is made to a method that is defined in class IabActivity.

launchInAppPurchaseFlow (this, SKU_GAS);

The value of the util package, the IabHelper class, and the IabActivity class is obvious. Look how simple the code is. That’s an indication of a good design. To understand how it works, we will look at the method and at the set up needed for it to work.

Let’s start with the onCreate method of the MainActivity. Method onCreate is a good place to get everything set up and check to see what purchases have already been made.

@Override public void onCreate(Bundle savedInstanceState) {

 // Start setup of in-app billing.
 // (Note that the work is done using methods in superclass
 // IabActivity. The original code had all the code here.)
 setupIabHelper (true, true);

 // Set a variable for convenient access
 // to the iab helper object.
 mHelper = getIabHelper ();

 // load game data
 updateUi ();

 // enable debug logging
 // (For a production application, you would set this to false).

The onCreate method looks pretty simple, but that is because most of the work is being done inside the setupIabHelper method of IabActivity. If you look inside IabActivity’s setupIabHelper method (next figure below), you will see that it creates an IabHelper object and then uses it to set up connections to a service that is running to handle in-app billing. When set up completes, note how the listener builds up a list of products to check on.

protected void setupIabHelper (final boolean showListedSkus, 
                               final boolean showErrors) {

setShowIabErrors (showErrors);
try {

 String base64EncodedPublicKey 
         = "--- YOUR APPLICATION KEY GOES HERE ---";

 // Create the helper, passing it our context
 // and the public key to verify signatures with
 IabHelper ih = new IabHelper(this, base64EncodedPublicKey);
 setIabHelper (ih); // sets pIabHelper

 // Start setup. This is asynchronous.
 ih.startSetup(new IabHelper.OnIabSetupFinishedListener() {
 public void onIabSetupFinished(IabResult result) {
  if (!result.isSuccess()) {
   if (pShowIabErrors)
    complain ("Problem setting up in-app billing: " + result);
   onIabSetupFailed (getIabHelper ());

  // IAB is fully set up. Get an inventory of stuff we own.
  // Build up a list of the SKUs so other parts of
  // of the app can get information on prices.
  ArrayList<String> skusToBeListed = null;
  if (showListedSkus) {
   skusToBeListed = new ArrayList<String> ();
   skusToBeListed.add (SKU_PREMIUM);
   skusToBeListed.add (SKU_GAS);
   skusToBeListed.add (SKU_INFINITE_GAS);
              (true, skusToBeListed, mGotInventoryListener);

} catch (Throwable ex) {



Notice the asynchronous query for information at the end. That method expects a listener for the last argument. We have one already set up in mGotInventoryListener. If you read the code for that listener, you will see that basically all it is doing is checking the result and calling either onIabSetupSucceeded or onIabSetupFailed. It is in method onIabSetupSucceeded (in IabActivity) where the checks are made.

The implementation of onIabSucceeded in IabActivity is shown below. This is the code in the superclass, so all subclasses benefit from the standard handling of set up. See how it checks on each of the three products in the app.  It takes immediate action for premium and infinite gas. Those two products are not consumable, which means users only have to purchase them one time. Once purchased, the user has them forever. For that to work, the code in onCreate has to check to if they have already been purchased. For those two products, it sets two global variables.

From class IabActivity:

void onIabSetupSucceeded (IabHelper h, 
                          IabResult result, Inventory inventory) {
 // Check for the in-app purchases of items.
 // (Do this here in the superclass so we write it only once.
 // Note that several global variables are set here.)

 // Do we have the premium upgrade?
 Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
 mIsPremium = (premiumPurchase != null 
               && verifyDeveloperPayload(premiumPurchase));

 // Do we have the infinite gas plan?
 Purchase infiniteGasPurchase = 
 mSubscribedToInfiniteGas = (infiniteGasPurchase != null &&

 // Check for gas delivery
 // -- if we own gas, we should fill up the tank immediately
 Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
 if (gasPurchase != null 
     && verifyDeveloperPayload(gasPurchase)) {
    pIabHelper.consumeAsync (gasPurchase, 


The third item, regular gas, is consumable. That means it can be used up and the user might have to purchase it multiple times, over the course of the game or sessions that a user has with the app. Since the gas item is consumable, the onCreate code initiates the operation to consume the item. That’s another asynchronous call that goes through the IabHelper object.

It’s not shown here, but if you check the definition of mConsumeFinishedListener, you will see how a successful call results in a callback to the onIabConsumeItemSucceeded method. I did it that way so the MainActivity, which is a subclass of IabActivity, could do its own special handling for consuming that item. That is shown below.

In MainActivity:

 * Called when consumption of a purchase item succeeds.
 * SKU_GAS is the only consumable item. 
 * So this is the place where the tank is filled.

void onIabConsumeItemSucceeded 
       (IabHelper h, Purchase purchase, IabResult result) {
 super.onIabConsumeItemSucceeded (h, purchase, result);

 // Update the state of the app and the ui
 // to show the item we purchased and consumed.
 String purchaseSku = purchase.getSku (); 
 if (purchaseSku.equals(SKU_GAS)) {
 if (result.isSuccess()) {
    // successfully consumed, so we apply the effects 
    // of the item in our game world's logic.
    // That means filling the gas tank a bit.
    mTank = mTank == TANK_MAX ? TANK_MAX : mTank + 1;
    alert ("You filled 1/4 tank. Your tank is now "
           + String.valueOf(mTank) + "/4 full!");
 } else {
   complain("Error while consuming regular gas: " + result);



The tank is filled up some and then the user interface is updated.

(I have to admit that as I write this explanation now that I am not completely sure that the way I have broken this code down is ideal. In my real app, it worked out pretty well to have the extra methods (like onIabConsumeItemSucceeded). Anyway, it’s always a good thing to reflect on the code you build and be open to restructuring it. What I was after was more common code in a superclass. That’s a good thing if it saves you work in your subclasses. So, that is something for you to think about in your own app.)

Initiating Purchases in MainActivity

Let’s go back to the point where a purchase starts and examine it in more detail.  A purchase begins when the user touches one of the purchase buttons.


For the “Buy Gas” the following code in MainActivity runs:

public void onBuyGasButtonClicked(View arg0) {
 if (mTank >= TANK_MAX) {
 complain("Your tank is full. Drive around a bit!");

 // Set up to show and wait screen.
 // Launch the gas purchase UI flow.
 launchInAppPurchaseFlow (this, SKU_GAS);


It changes the user interface to show the wait screen, and then it launches the in-app purchase flow, using method launchInAppPurchaseFlow in superclass IabActivity.

protected void launchInAppPurchaseFlow (Activity a, String sku) {
 launchInAppPurchaseFlow (a, sku, 

protected void launchInAppPurchaseFlow 
                 (Activity a, String sku, String itemType) {
 IabHelper h = getIabHelper ();
 if (h != null) {
    h.launchPurchaseFlow (a, sku, itemType, RC_PURCHASE_REQUEST,
                          mPurchaseFinishedListener, "");

Notice that the real work gets done in IabHelper, the class defined in the util package. Basically, it is setting up an Intent so an activity can be started to do the work. The return code RC_PURCHASE_REQUEST is defined in IabActivity, as is the onActivityResult method. The onActivityResult method in IabActivity runs when the second activity completes. As you see below, it lets the IabHelper do the work.

@Override protected void onActivityResult 
                           (int requestCode, 
                            int resultCode, Intent data) {
 switch (requestCode) {

 // Handle the purchase request here.
 if (pIabHelper != null) {
  // The interesting work is done in IabHelper class.
  // See its handleActivityResult method.
  if (!pIabHelper.handleActivityResult 
                   (requestCode, resultCode, data)) {
   // Not handled by the helper, so let other code do it.
   super.onActivityResult (requestCode, resultCode, data);


So much goes on in IabHelper. That’s a good thing for you me. We are left with a small number of places in our own activities where we have to react to in-app purchase requests. Also note that onActivityResult is defined in IabActivity rather than MainActivity. In an app with more than one activity doing in-app purchase calls, that works out well. There only has to be the one definition because the code does not change. MainActivity, and any future activities, are a little easier to implement and understand.

If you work through the rest of the code (below), you will see how two more of the handlers defined in IabActivity initiate more asynchronous calls and then make callbacks to some success and failure methods that are easily implemented in MainActivity. The two methods are onConsumeItemSucceeded and onConsumeItemFailed.

   = new IabHelper.OnIabPurchaseFinishedListener() {
 public void onIabPurchaseFinished 
              (IabResult result, Purchase purchase) {
   if (purchase.getSku().equals (SKU_PREMIUM)) {
     pIabHelper.consumeAsync (purchase, mConsumeFinishedListener);
   } else if (purchase.getSku().equals (SKU_GAS)) {
     pIabHelper.consumeAsync (purchase, mConsumeFinishedListener);
   } else if (purchase.getSku().equals (SKU_INFINITE_GAS)) {
     pIabHelper.consumeAsync (purchase, mConsumeFinishedListener);

   = new IabHelper.OnConsumeFinishedListener() {
 public void onConsumeFinished
  (Purchase purchase, IabResult result) {
 if (result.isSuccess ()) {
  synchronized (pIabHelper) {
   onIabConsumeItemSucceeded (pIabHelper, purchase, result);
 } else {
  complain ("Did not handle purchase: " 
            + purchase + " result: " + result);
  onIabConsumeItemFailed (pIabHelper);

The other two buttons are not much different than what I have shown for the “Buy Gas” button. Work through those, too, so you will have a complete understanding of consumable and non-consumable in-app products.

Additional Changes Needed for Your Own App

I have already talked about your own products sku strings. Once you have defined those in the Android Developer Console, you would update those in the Constants class.

In method setupIabHelper of IabActivity, there is a line you have to change so the code knows the application key for your app. Be sure to do that. Without it, your app will not be able to tie your product sku strings with the information you entered in the Android Developer Console.

protected void setupIabHelper
 (final boolean showListedSkus, final boolean showErrors) {

 String base64EncodedPublicKey = "YOUR APPLICATION KEY GOES HERE";


The image below (from Part 1 of this article) shows where to look for the public key. It is the very long string that is blurred out and highlighted with the orange text.


There is a method in the TrivialDrive sample code named “verifyDeveloperPayload”. It is there to ensure that all purchase attempts are valid. I have not implemented this method for my app, but at some point, I should, and you should too. Very good guidance has been provided by the author of the sample app, Bruno Oliveira.

boolean verifyDeveloperPayload(Purchase p) {

String payload = p.getDeveloperPayload();

 * 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.

return true;

Source Code

The source code for the modified TrivialDrive app can be found at the website. Click here: zip file of finished sample for part 2.


The sample TrivialDrive app provided by Google is very well done. There is so much to learn from it. Thanks go to Bruno Oliveira from Google.


How To Implement In-App Billing in Android – Part 1 – the first part of my blog article. Be sure to read it for details about setting up you in-app products, packaging your app, and release your app.

Preparing Your In-App Billing Application – the primary reference with the TrivialDrive example from the Google team.

Android Fragment for an Item in a Store – A sample app that shows how to build a store listing for products. Also see the follow-up article on store items.

Double Star app – This is my space war app. It includes in-app products. If you’d to see how all the pieces for in-app billing came together, please try the game.

Posted in Android | Tagged , , , , | 6 Comments