title: Android In App Billing: Purchase keeps getting -1005 response user cancelled
body: <p>This is my first time working with In App Billing in android. My goal is to create purchasable item somewhat like pro version unlock for the app.</p>
  
  <p>My problem is that it keeps giving me these errors.</p>
  
  <p><a href="https://i.stack.imgur.com/iPJuj.png"><img src="https://i.stack.imgur.com/iPJuj.png" alt="enter image description here"></a></p>
  
  <p><a href="https://i.stack.imgur.com/Af370.png"><img src="https://i.stack.imgur.com/Af370.png" alt="enter image description here"></a></p>
  
  <p>Please take note that the license key is correct, my google account is already added as a tester in the console, the product sku already exists and alpha build of the apk is already uploaded to the console.</p>
  
  <p>Here's my code,</p>
  
  <pre><code>public class ProVersionActivity extends AppCompatActivity {
  
      public static final String TAG = "ProVersionActivity";
      public static final String SKU_PRO_VERSION = "vollversion";
      private boolean mProVersionPurchased = false;
      private String mPayload = "";
  
      //(arbitrary) request code for the purchase flow
      public static final int RC_REQUEST = 10001;
  
      private Button mInAppPurchaseButton = null;
      private WebView mWebView = null;
      private IabHelper mHelper = null;
  
      private ProgressDialog mProgressDialog = null;
  
      private static final String LICENSE_KEY = "LICENSE_KEY";
  
      //Listener that's called when we finish querying the items and subscriptions we own
      private IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
          public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
              Log.d(TAG, "Query inventory finished.");
  
              // Have we been disposed of in the meantime? If so, quit.
              if (mHelper == null) return;
  
              // Is it a failure?
              if (result.isFailure()) {
                  complain("Failed to query inventory: " + result);
                  return;
              }
  
              Log.d(TAG, "Query inventory was successful.");
  
              /*
               * 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 infinite gas plan
              Purchase proVersionPurchase = inventory.getPurchase(SKU_PRO_VERSION);
              mProVersionPurchased = (proVersionPurchase != null &amp;&amp; verifyDeveloperPayload(proVersionPurchase));
              Log.d(TAG, "User " + (mProVersionPurchased ? "HAS" : "DOES NOT HAVE") + " proversion");
  
              if(mProVersionPurchased){
                  //this means user already purchased the full version
                  setProversionPurchased(mProVersionPurchased);
              }
  
              Log.d(TAG, "Initial inventory query finished");
          }
      };
  
      // Callback for when a purchase is finished
      private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
          public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
  
              Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
  
              // if we were disposed of in the meantime, quit.
              if (mHelper == null) return;
  
              if (result.isFailure()) {
                  Log.d(TAG, "Error purchasing: " + result);
                  complain("Error purchasing: " + result);
                  //setWaitScreen(false);
                  dismissProgressDialog();
                  return;
              }
              if (!verifyDeveloperPayload(purchase)) {
                  Log.d(TAG, "Error purchasing. Authenticity verification failed.");
                  complain("Error purchasing. Authenticity verification failed.");
                  //setWaitScreen(false);
                  dismissProgressDialog();
                  return;
              }
  
              Log.d(TAG, "Purchase successful.");
  
             if (purchase.getSku().equals(SKU_PRO_VERSION)) {
  
                 // bought the infinite gas subscription
                 Log.d(TAG, "Proversion purchased.");
                 alert("Thank you for purchasing the Proversion!");
                 mProVersionPurchased = true;
                 setProversionPurchased(mProVersionPurchased);
                 //setWaitScreen(false);
                 dismissProgressDialog();
  
                 ProVersionActivity.this.finish();
             }
          }
      };
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
  
          setContentView(R.layout.activity_pro_version);
          getSupportActionBar().setTitle(R.string.vollversion);
  
          //for the progress dialog
          mProgressDialog = new ProgressDialog(this);
          mProgressDialog.setCancelable(false);
          mProgressDialog.setCanceledOnTouchOutside(false);
          mProgressDialog.setMessage("Processing...");
          mProgressDialog.setIndeterminate(true);
  
          String lang = getString(R.string.lang);
  
          mWebView = (WebView) findViewById(R.id.webView);
          mWebView.getSettings().setJavaScriptEnabled(true);
          mWebView.loadUrl("file:///android_asset/html/" + lang + "_iap.htm");
  
          /**
           * preparing in app billing
           * */
          String base64EncodedPublicKey = LICENSE_KEY;
          // compute your public key and store it in base64EncodedPublicKey
          mHelper = new IabHelper(this, base64EncodedPublicKey);
          // enable debug logging (for a production application, you should set this to false).
          mHelper.enableDebugLogging(true);
  
          mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
              public void onIabSetupFinished(IabResult result) {
  
                  if (!result.isSuccess()) {
                      Log.d(TAG, "Problem setting up In-app Billing: " + result);
                  }
  
                  // Have we been disposed of in the meantime? If so, quit.
                  if (mHelper == null)
                      return;
  
                  // IAB is fully set up. Now, let's get an inventory of stuff we own.
                  Log.d(TAG, "Setup successful. Querying inventory.");
                  mHelper.queryInventoryAsync(mGotInventoryListener);
              }
          });
  
          mInAppPurchaseButton = (Button) findViewById(R.id.in_app_purchase_button);
          mInAppPurchaseButton.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
  
                  if (!mHelper.subscriptionsSupported()) {
                      Log.d(TAG, "Subscriptions not supported on your device yet. Sorry!");
                      complain("Subscriptions not supported on your device yet. Sorry!");
                      return;
                  }
  
                  //setWaitScreen(true);
                  showProgressDialog();
                  Log.d(TAG, "Launching purchase flow for pro version purchase.");
                  mHelper.launchPurchaseFlow(
                          ProVersionActivity.this,
                          SKU_PRO_VERSION,
                          //IabHelper.ITEM_TYPE_SUBS,
                          RC_REQUEST,
                          mPurchaseFinishedListener,
                          mPayload);
              }
          });
      }
  
      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  
          Log.d(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 {
              Log.d(TAG, "onActivityResult handled by IABUtil.");
          }
      }
  
      private void setProversionPurchased(boolean value){
  
          //temporarily allow the purchase immediately for development purposes.
          SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(ProVersionActivity.this);
          SharedPreferences.Editor editor = sharedPref.edit();
          editor.putBoolean(SettingsActivity.PREF_KEY_PRO_VERSION, value);
          editor.apply();
  
          Toast.makeText(this,"Pro version purchased!",Toast.LENGTH_LONG).show();
      }
  
      private void complain(String message) {
          Log.e(TAG, "Error: " + message);
          alert("Error: " + message);
      }
  
      private void alert(String message) {
          AlertDialog.Builder bld = new AlertDialog.Builder(this);
          bld.setMessage(message);
          bld.setNeutralButton("OK", null);
          Log.d(TAG, "Showing alert dialog: " + message);
          bld.create().show();
      }
  
      /** Verifies the developer payload of a purchase. */
      private boolean verifyDeveloperPayload(Purchase p) {
  
          mPayload = p.getDeveloperPayload();
          Log.d(TAG, "payload: "+mPayload);
  
          /*
           * 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;
      }
  
      /**
       * Method to display registration progress dialog.
       */
      private void showProgressDialog(){
  
          /* Dismiss existing dialog if any. */
          dismissProgressDialog();
  
          new DialogAsyncTask().execute(new String[]{});
      }
  
      private void dismissProgressDialog(){
          /*
          if(mProgressDialog != null &amp;&amp; mProgressDialog.isShowing()){
              mProgressDialog.dismiss();
          }
          */
          RUN_PROGRESS_DIALOG = false;
      }
  
      public static boolean RUN_PROGRESS_DIALOG = true;
  
      private class DialogAsyncTask extends AsyncTask&lt;String,String,String&gt; {
  
          @Override
          protected void onPreExecute() {
              super.onPreExecute();
              mProgressDialog.show();
          }
  
          @Override
          protected String doInBackground(String... strings) {
  
              while(RUN_PROGRESS_DIALOG){}
  
              return null;
          }
  
          @Override
          protected void onPostExecute(String s) {
              super.onPostExecute(s);
              mProgressDialog.dismiss();
          }
      }
  
      // We're being destroyed. It's important to dispose of the helper here!
      @Override
      public void onDestroy() {
          super.onDestroy();
  
          // very important:
          Log.d(TAG, "Destroying helper.");
          if (mHelper != null) {
              mHelper.dispose();
              mHelper = null;
          }
      }
  }
  </code></pre>
  
  <p>The code keeps return -1005 response in which I couldn't find any reference from android developer site. I already spent countless of days finding the problems and googling please help me. Any comments and answers will be greatly appreciated. Thank you so much!</p>