title: Setting up v3 of in-app billing
body: <p>I have an app on the market.  My next version I want to implement an in-app purchase.  I have been following the (long) guide for <a href="http://developer.android.com/training/in-app-billing/index.html" rel="nofollow">setup of v3 of in-app billing</a>.  I completed the first 3 lessons from that link but now my code has a load of errors that all are on the same variable.</p>
  
  <p>In the code below, <code>spreadsheet</code> is my PRODUCT_ID from my Developer Console for what is being purchased.  Every time the variable <code>spreadsheet</code> is used, the error is:  "Spreadsheet cannot be resolved to a variable."</p>
  
  <pre><code>    public class BibleStudy extends SwarmActivity {
          Context c;
          IabHelper mHelper;
  
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              requestWindowFeature(Window.FEATURE_NO_TITLE);
              setContentView(R.layout.biblestudy);
  
              c = this;
  
          String base64EncodedPublicKey = a + b + d + e + f + g + h + i + j + k;
  
          // Create the helper, passing it our context and the public key to verify signatures with
          mHelper = new IabHelper(this, base64EncodedPublicKey);
  
          // Start setup. This is asynchronous and the specified listener will be called once setup completes.
          mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
              public void onIabSetupFinished(IabResult result) {
  
                  if (!result.isSuccess()) {
                      // Oh noes, there was a problem.
                      complain("Problem setting up in-app billing: " + result);
                      return;
                  }
  
                  // Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own.
                  mHelper.queryInventoryAsync(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) {
              if (result.isFailure()) {
                  complain("Failed to query inventory: " + result);
                  return;
              }
  
              /*
               * Check for items we own. Notice that for each purchase, we check
               * the developer payload to see if it's correct! See
               * verifyDeveloperPayload().
               */
  
              // Do we have the premium upgrade?
              Purchase spreadsheetPurchase = inventory.getPurchase(spreadsheet);
  
              updateUi();
          }
      };
  
      // User clicked the "Download Spreadsheet!" button.
      public void onBuyButtonClick(View v) {
  
          // launch the gas purchase UI flow.
          // We will be notified of completion via mPurchaseFinishedListener
  
          /* 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 = ""; 
  
          mHelper.launchPurchaseFlow(this, spreadsheet, 10001, mPurchaseFinishedListener, payload);
      }
  
      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  
          // 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);
          }
      }
  
      /** Verifies the developer payload of a purchase. */
      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;
      }
  
      // Callback for when a purchase is finished
      IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
          public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
              if(result.isFailure()) {
                  complain("Error purchasing: " + result);
                  return;
              }
  
              if(!verifyDeveloperPayload(purchase)) {
                  complain("Error purchasing. Authenticity verification failed.");
                  return;
              }
  
              else if(purchase.getSku().equals(spreadsheet)) {
                  // bought the premium upgrade!
                  alert("Thank you for upgrading to premium!");
  //                mIsPremium = true;
                  updateUi();
              }
          }
      };
  
      // updates UI to reflect model
      public void updateUi() {
  
          // MATT: update a TextView to show link after purchase is done.
  
  //        // update the car color to reflect premium status or lack thereof
  //        ((ImageView)findViewById(R.id.free_or_premium)).setImageResource(mIsPremium ? R.drawable.premium : R.drawable.free);
  //
  //        // "Upgrade" button is only visible if the user is not premium
  //        findViewById(R.id.upgrade_button).setVisibility(mIsPremium ? View.GONE : View.VISIBLE);
  //
  //        // "Get infinite gas" button is only visible if the user is not subscribed yet
  //        findViewById(R.id.infinite_gas_button).setVisibility(mSubscribedToInfiniteGas ? 
  //                View.GONE : View.VISIBLE);
  //
  //        // update gas gauge to reflect tank status
  //        if (mSubscribedToInfiniteGas) {
  //            ((ImageView)findViewById(R.id.gas_gauge)).setImageResource(R.drawable.gas_inf);
  //        }
  //        else {
  //            int index = mTank &gt;= TANK_RES_IDS.length ? TANK_RES_IDS.length - 1 : mTank;
  //            ((ImageView)findViewById(R.id.gas_gauge)).setImageResource(TANK_RES_IDS[index]);
  //        }        
      }
  
      void complain(String message) {
          alert("Error: " + message);
      }
  
      void alert(String message) {
          AlertDialog.Builder bld = new AlertDialog.Builder(this);
          bld.setMessage(message);
          bld.setNeutralButton("OK", null);
          bld.create().show();
      }
  
      @Override
      public void onDestroy() {
          super.onDestroy();
          if(mHelper != null) mHelper.dispose();
          mHelper = null;
      }
  }
  </code></pre>
  
  <p>What I want to do when the purchase is successfully completed is provide the user with a link.  So I guess what I need is something that I can verify a purchase is complete with and then I can display a previously invisible TextView that provides them with the link.</p>
  
  <p>My question is what have I done wrong from the tutorial and how can I get the errors to go away that appear on everyone the variable <code>spreadsheet</code> is used?</p>