Please refer to the earlier question for a more comprehensive understanding Q1, followed by Q2.
I have identified the reason why my handlePurchase() method is not being invoked. In a previous successful purchase, the method did not get called, and even in that instance, the SharedPreferences were not accessed.
Now, the method is correctly entering the appropriate if statement where the PurchaseResponse Code is ITEM_ALREADY_OWNED. However, the purchases variable is being populated with an empty value, not a null value. This is causing an issue for the handlePurchase() method, as it expects the purchase variable to contain some information.
Here is the relevant code:
public class HelpActivity extends AppCompatActivity {
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = new AcknowledgePurchaseResponseListener() {
@Override
public void onAcknowledgePurchaseResponse(@NonNull BillingResult billingResult) {
Toast.makeText(HelpActivity.this, "Acknowledge", Toast.LENGTH_SHORT).show();
}
};
private BillingClient billingClient;
private final PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null && !purchases.isEmpty()) {
Purchase purchase = purchases.get(0);
handlePurchase(purchase);
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
Toast.makeText(HelpActivity.this, "Purchase Canceled", Toast.LENGTH_SHORT).show();
//Note!!!! only this toast message is being shown in this entre process
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
Toast.makeText(HelpActivity.this, "You already own the item, Please restore the purchase ", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.BILLING_UNAVAILABLE) {
Toast.makeText(HelpActivity.this, "BILLING_UNAVAILABLE", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ERROR) {
Toast.makeText(HelpActivity.this, "ERROR", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.DEVELOPER_ERROR) {
Toast.makeText(HelpActivity.this, "DEVELOPER_ERROR", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ITEM_NOT_OWNED) {
Toast.makeText(HelpActivity.this, "ITEM_NOT_OWNED", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ITEM_UNAVAILABLE) {
Toast.makeText(HelpActivity.this, "ITEM_UNAVAILABLE", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED) {
Toast.makeText(HelpActivity.this, "FEATURE_NOT_SUPPORTED", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.NETWORK_ERROR) {
Toast.makeText(HelpActivity.this, "FEATURE_NOT_SUPPORTED", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.SERVICE_DISCONNECTED) {
Toast.makeText(HelpActivity.this, "SERVICE_DISCONNECTED", Toast.LENGTH_SHORT).show();
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE) {
Toast.makeText(HelpActivity.this, "SERVICE_UNAVAILABLE", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(HelpActivity.this, " Debug:-" + billingResult.getDebugMessage(), Toast.LENGTH_SHORT).show();
}
}
};
private MaterialButton removeAdsBtn;
private MaterialButton restorePurchaseBtn;
private ProductDetails productDetailsFinal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_help_avtivity);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // Set vertical orientation
Window window = this.getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.setStatusBarColor(this.getResources().getColor(R.color.black));
}
setupBillingClient();
restorePurchaseBtn = findViewById(R.id.restoreAdsBtn);
removeAdsBtn = findViewById(R.id.removeAdsBtn);
// Initialize BillingClient
restorePurchaseBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
restorePurchases();
}
});
removeAdsBtn.setOnClickListener(view -> {
// Call the method to initiate the billing flow
initiateBillingFlow();
billingClient = null;
});
}
public void setupBillingClient() {
billingClient = BillingClient.newBuilder(this).setListener(purchasesUpdatedListener).enablePendingPurchases().build();
establishConnection();
}
void establishConnection() {
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
QueryPurchase();
}
}
@Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
establishConnection();
}
});
}
public void QueryPurchase() {
QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder().setProductList(ImmutableList.of(QueryProductDetailsParams.Product.newBuilder().setProductId("removeads_rickroll").setProductType(BillingClient.ProductType.INAPP).build())).build();
billingClient.queryProductDetailsAsync(queryProductDetailsParams, (billingResult, productDetailsList) -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// Check if the productDetailsList is not empty
if (!productDetailsList.isEmpty()) {
for (ProductDetails productDetails : productDetailsList) {
productDetailsFinal = productDetails;
}
} else {
Toast.makeText(HelpActivity.this, "(QueryPurchase) No Product Details Available", Toast.LENGTH_SHORT).show();
}
}
});
}
public void initiateBillingFlow() {
if (productDetailsFinal != null) {
ImmutableList<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
ImmutableList.of(
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetailsFinal)
.build());
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.build();
billingClient.launchBillingFlow(HelpActivity.this, billingFlowParams);
} else {
Toast.makeText(HelpActivity.this, "(initiateBillingFlow) No Product Details Available", Toast.LENGTH_SHORT).show();
}
}
private void handlePurchase(Purchase purchase) {
ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();
ConsumeResponseListener listener = (billingResult, purchaseToken) -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// Handle the success of the consume operation.
}
};
billingClient.consumeAsync(consumeParams, listener);
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
//Verify Purchase
if (!verifyValidSignature(purchase.getOriginalJson(), purchase.getSignature())) {
Toast.makeText(this, "Error:- Invalid Purchase", Toast.LENGTH_SHORT).show();
return;
}
if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();
billingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
// Grant the user access to remove ads
// Save the purchase details to SharedPreferences to remember the purchase
Toast.makeText(HelpActivity.this, "Thank you for the purchase", Toast.LENGTH_SHORT).show();
Toast.makeText(HelpActivity.this, "Restarting the app, Please wait ...", Toast.LENGTH_SHORT).show();
SharedPreferences preferences = getSharedPreferences("adremoveSP", MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("ads_removed", true);
editor.apply();
System.exit(0);
}
} else if (purchase.getPurchaseState() == Purchase.PurchaseState.UNSPECIFIED_STATE) {
Toast.makeText(this, "UNSPECIFIED_STATE", Toast.LENGTH_SHORT).show();
} else if (purchase.getPurchaseState() == Purchase.PurchaseState.PENDING) {
Toast.makeText(this, "PENDING", Toast.LENGTH_SHORT).show();
}
}
private boolean verifyValidSignature(String originalJson, String signature) {
try {
String base64Key = "<My Base64Key>";
return Verify.verifyPurchase(base64Key, originalJson, signature);
} catch (IOException e) {
return false;
}
}
public void restorePurchases() {
/*
Toast.makeText(HelpActivity.this,"Entered into restorePurchase",Toast.LENGTH_SHORT).show();
*/
if (productDetailsFinal!= null || !productDetailsFinal.getProductId().isEmpty()) {
Toast.makeText(HelpActivity.this,"Entered into restorePurchase purchae available",Toast.LENGTH_SHORT).show();
Toast.makeText(HelpActivity.this, "Successfully restored", Toast.LENGTH_SHORT).show();
SharedPreferences preferences = getSharedPreferences("adremoveSP", MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("ads_removed", true);
editor.apply();
System.exit(0);
} else {
Toast.makeText(HelpActivity.this, "Oops, No purchase found.", Toast.LENGTH_SHORT).show();
SharedPreferences preferences = getSharedPreferences("adremoveSP", MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("ads_removed", false);
editor.apply();
}
}
/* protected void onResume() {
super.onResume();
billingClient.queryPurchasesAsync(QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build(), (billingResult, list) -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
for (Purchase purchase : list) {
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED && !purchase.isAcknowledged()) {
handlePurchase(purchase);
}
}
}
});
}*/
}
now as i have added !purchase.IsEmpty() now the app is goin in the last else statement , and there to the billingResult is null where i added
billingResult.getDebugMessage()
Please could anyone help me with this , im stuck on this from a week now
Edit :- As the List Of Purchase was returing null and this condition
billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED && purchases != null && !purchases.isEmpty()
in the previous code was not getting executed due to empty list , now i have passed just a toast message there and removed the && purchases != null && !purchases.isEmpty() , now im thinking to use a seprate restore button that restore any previous purchase , but then im confusd about how would i get the purchase list , i dont know what is right and wrong