package com.aptoide.amethyst.openiab; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.support.v4.app.DialogFragment; import android.telephony.TelephonyManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.aptoide.amethyst.Aptoide; import com.aptoide.amethyst.R; import com.aptoide.amethyst.configuration.AptoideConfiguration; import com.aptoide.amethyst.database.AptoideDatabase; import com.aptoide.models.PaymentServices; import com.bumptech.glide.Glide; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.octo.android.robospice.persistence.DurationInMillis; import com.octo.android.robospice.persistence.exception.SpiceException; import com.octo.android.robospice.request.listener.RequestListener; import com.paypal.android.sdk.payments.ProofOfPayment; import org.json.JSONObject; import org.onepf.oms.BillingBinder; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import com.aptoide.amethyst.openiab.webservices.BasePurchaseStatusRequest; import com.aptoide.amethyst.openiab.webservices.IabPurchaseStatusRequest; import com.aptoide.amethyst.openiab.webservices.IabPurchasesRequest; import com.aptoide.amethyst.openiab.webservices.IabSkuDetailsRequest; import com.aptoide.amethyst.openiab.webservices.PayProductRequestBase; import com.aptoide.amethyst.openiab.webservices.PaypalPurchaseAuthorizationRequest; import com.aptoide.amethyst.openiab.webservices.json.IabPurchaseStatusJson; import com.aptoide.amethyst.openiab.webservices.json.IabPurchasesJson; import com.aptoide.amethyst.openiab.webservices.json.IabSkuDetailsJson; import com.aptoide.amethyst.dialogs.ProgressDialogFragment; public class IABPurchaseActivity extends BasePurchaseActivity { // Response result codes public static final int RESULT_OK = 0; public static final int RESULT_USER_CANCELED = 1; public static final int RESULT_BILLING_UNAVAILABLE = 3; public static final int RESULT_ITEM_UNAVAILABLE = 4; public static final int RESULT_DEVELOPER_ERROR = 5; public static final int RESULT_ERROR = 6; public static final int RESULT_ITEM_ALREADY_OWNED = 7; public static final int RESULT_ITEM_NOT_OWNED = 8; // Keys for the responses public static final String RESPONSE_CODE = "RESPONSE_CODE"; public static final String DETAILS_LIST = "DETAILS_LIST"; public static final String BUY_INTENT = "BUY_INTENT"; public static final String INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA"; public static final String INAPP_DATA_SIGNATURE = "INAPP_DATA_SIGNATURE"; public static final String INAPP_PURCHASE_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST"; public static final String INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST"; public static final String INAPP_DATA_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST"; public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN"; // Item types public static final String ITEM_TYPE_INAPP = "inapp"; public static final String ITEM_TYPE_SUBS = "subs"; private int apiVersion; private String type; private String sku; private String developerPayload; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.page_app_purchase); final Intent intent = getIntent(); developerPayload = intent.getStringExtra("developerPayload"); apiVersion = intent.getIntExtra("apiVersion", 3); sku = intent.getStringExtra("sku"); type = intent.getStringExtra("type"); //sku = "com.aptoide.partners"; //token = "27286b943179065fcef3b6adcafe8680d8515e4652010602c45f6"; final String user = intent.getStringExtra("user"); if (user == null) { // AccountManager.get(this).addAccount(Aptoide.getConfiguration().getAccountType(), AptoideConfiguration.AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, null, null, this, new AccountManagerCallback<Bundle>() { @Override public void run(AccountManagerFuture<Bundle> future) { try { String account = future.getResult().getString(AccountManager.KEY_ACCOUNT_NAME); if(account!=null){ updateUI(account); }else { finish(); } } catch (Exception e) { e.printStackTrace(); finish(); } } }, new Handler(Looper.getMainLooper())); } else { updateUI(user); } findViewById(R.id.buttonCancel).setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { Log.d("AptoideinAppBilling", "Purchase Cancelled"); intent.putExtra(BillingBinder.RESPONSE_CODE, BillingBinder.RESULT_USER_CANCELED); setResult(RESULT_OK, intent); finish(); } }); } private void updateUI(String user){ //Intent billingIntent = new Intent(this, BillingService.class); //bindService(billingIntent, mConnection, BIND_AUTO_CREATE); ((TextView) findViewById(R.id.username)).setText(getString(R.string.account) + ": " + user); thingThatisNotAService(); } @Override protected boolean makeExtraTestsOnPurchaseOk(IabPurchaseStatusJson iabPurchaseStatusJson) { return !sku.equals(iabPurchaseStatusJson.getPublisherResponse().getItem().get(0)); } private Bundle getPurchases(int apiVersion, String packageName, String type) throws RemoteException { Log.d("AptoideBillingService", "[getPurchases]: " + packageName + " " + type); final Bundle result = new Bundle(); if (apiVersion < 3 || !(ITEM_TYPE_INAPP.equals(type) || ITEM_TYPE_SUBS.equals(type))) { result.putInt(RESPONSE_CODE, RESULT_DEVELOPER_ERROR); return result; } AccountManager accountManager = AccountManager.get(this); Account[] accounts = accountManager.getAccountsByType(Aptoide.getConfiguration().getAccountType()); if(accounts.length == 0) { Log.d("AptoideBillingService", "BillingUnavailable: user not logged in"); result.putStringArrayList(INAPP_PURCHASE_ITEM_LIST, new ArrayList<String>()); result.putStringArrayList(INAPP_PURCHASE_DATA_LIST, new ArrayList<String>()); result.putStringArrayList(INAPP_DATA_SIGNATURE_LIST, new ArrayList<String>()); result.putInt(RESPONSE_CODE, RESULT_OK); return result; } try { String token = accountManager.blockingGetAuthToken(accounts[0], "Full access", true); if(token != null) { final CountDownLatch latch = new CountDownLatch(1); IabPurchasesRequest request = new IabPurchasesRequest(); request.setApiVersion(Integer.toString(apiVersion)); request.setPackageName(packageName); request.setType(type); request.setToken(token); spiceManager.execute(request, packageName + "-getPurchases-"+type, DurationInMillis.ONE_SECOND*5, new RequestListener<IabPurchasesJson>() { @Override public void onRequestFailure(SpiceException spiceException) { result.putInt(RESPONSE_CODE, RESULT_ERROR); latch.countDown(); } @Override public void onRequestSuccess(IabPurchasesJson response) { if("OK".equals(response.getStatus())) { ArrayList<String> purchaseItemList = (ArrayList<String>) response.getPublisher_response().getItemList(); ArrayList<String> purchaseSignatureList = (ArrayList<String>) response.getPublisher_response().getSignatureList(); ArrayList<String> purchaseDataList = new ArrayList<String>(); for(IabPurchasesJson.PublisherResponse.PurchaseDataObject purchase : response.getPublisher_response().getPurchaseDataList()) { Log.d("AptoideBillingService", "Purchase: " + purchase.getJson()); purchaseDataList.add(purchase.getJson()); } result.putStringArrayList(INAPP_PURCHASE_ITEM_LIST, purchaseItemList); result.putStringArrayList(INAPP_PURCHASE_DATA_LIST, purchaseDataList); result.putStringArrayList(INAPP_DATA_SIGNATURE_LIST, purchaseSignatureList); if(response.getPublisher_response().getInapp_continuation_token() != null) { result.putString(INAPP_CONTINUATION_TOKEN, response.getPublisher_response().getInapp_continuation_token()); } result.putInt(RESPONSE_CODE, RESULT_OK); } else { result.putInt(RESPONSE_CODE, RESULT_DEVELOPER_ERROR); } latch.countDown(); } }); latch.await(); } } catch (Exception e) { e.printStackTrace(); result.putInt(RESPONSE_CODE, RESULT_ERROR); } return result; } protected boolean TestifPurchased() { try { Bundle bundle = getPurchases(apiVersion, packageName, type); for(String json : bundle.getStringArrayList("INAPP_PURCHASE_ITEM_LIST")){ if(sku.equals(json)){ return true; } } } catch (RemoteException e) { e.printStackTrace(); } catch (Exception e){ finish(); return false; } return false; } @Override protected void requestsetExtra(PayProductRequestBase pprb) { pprb.setApiVersion(String.valueOf(apiVersion)); pprb.setDeveloperPayload(developerPayload); } private String getMccCode(String networkOperator) { return networkOperator == null ? "" : networkOperator.substring(0, mncPortionLength(networkOperator)); } private String getMncCode(String networkOperator) { return networkOperator == null ? "" : networkOperator.substring(mncPortionLength(networkOperator)); } private int mncPortionLength(String networkOperator) { return Math.min(3, networkOperator.length()); } protected IabSkuDetailsRequest BuildIabSkuDetailsRequest(){ return new IabSkuDetailsRequest(); } private void thingThatisNotAService(){ final Activity THIS = this; new Thread(new Runnable() { @Override public void run() { try{ repo = new AptoideDatabase(Aptoide.getDb()).getRollbackRepo(packageName); }catch (Exception e) { e.printStackTrace(); } if(TestifPurchased()){ Intent intent = new Intent(); intent.putExtra(BillingBinder.RESPONSE_CODE, BillingBinder.RESULT_ITEM_ALREADY_OWNED); setResult(RESULT_OK, intent); finish(); return; } //token = accountManager.blockingGetAuthToken(accountManager.getAccountsByType(AccountGeneral.ACCOUNT_TYPE)[0], "Full access", true); //String token = "27286b943179065fcef3b6adcafe8680d8515e4652010602c45f6"; final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); IabSkuDetailsRequest request = BuildIabSkuDetailsRequest(); request.setPackageName(packageName); request.setToken(token); //request.setOemid(((AptoideConfigurationPartners) Aptoide.getConfiguration()).PARTNERID); if (telephonyManager != null && telephonyManager.getSimState()==TelephonyManager.SIM_STATE_READY) { request.setMcc(getMccCode(telephonyManager.getNetworkOperator())); request.setMnc(getMncCode(telephonyManager.getNetworkOperator())); simcc = telephonyManager.getSimCountryIso(); request.setSimcc(simcc); } ArrayList<String> item_list = new ArrayList<String>(); item_list.add(sku); request.setApiVersion(Integer.toString(apiVersion)); for (String itemId : item_list) { request.addToSkuList(itemId); Log.d("Aptoide-Binder", "Sku details request for " + itemId); } spiceManager.execute(request, packageName + "-getSkuDetails-" + request.getSkuList() + token, DurationInMillis.ONE_MINUTE, new RequestListener<IabSkuDetailsJson>() { @Override public void onRequestFailure(SpiceException spiceException) { Intent intent = new Intent(); intent.putExtra(BillingBinder.RESPONSE_CODE, BillingBinder.RESULT_ERROR); setResult(RESULT_OK, intent); finish(); } @Override public void onRequestSuccess(IabSkuDetailsJson response) { ArrayList<String> detailsList = new ArrayList<String>(); if ("OK".equals(response.getStatus())) { for (IabSkuDetailsJson.PurchaseDataObject details : response.getPublisher_response().getDetailss_list()) { String s = ""; try { s = new ObjectMapper().writeValueAsString(details); } catch (JsonProcessingException e) { e.printStackTrace(); } detailsList.add(s); Log.d("AptoideBillingService", "Sku Details: " + s); } LinearLayout paymentMethodsLayout = (LinearLayout) findViewById(R.id.payment_methods); paymentMethodsLayout.removeAllViews(); Button button; if (response.getPayment_services()!=null && response.getPayment_services().isEmpty()) { TextView noPaymentsFound = new TextView(THIS); noPaymentsFound.setText(R.string.no_payments_available); paymentMethodsLayout.addView(noPaymentsFound); }else if(response.getPayment_services() !=null ){ for (PaymentServices service : response.getPayment_services()) { int serviceCode = servicesList.get(service.getShort_name()); switch (serviceCode) { case PAYPAL_CODE: for (PaymentServices.PaymentType type : service.getTypes()) { if ("future".equals(type.getReqType())) { button = (Button) LayoutInflater.from(THIS).inflate(R.layout.button_paypal, null); button.setText(type.getLabel() + " - " + service.getPrice() + " " + service.getSign()); paymentMethodsLayout.addView(button); PaypalPurchaseAuthorizationRequest request = new PaypalPurchaseAuthorizationRequest(); request.setToken(token); HasAuthorization hasAuthorization = new HasAuthorization(button); hasAuthorization.setCurrency(service.getCurrency()); hasAuthorization.setPrice(service.getPrice()); hasAuthorization.setTax(service.getTaxRate()); spiceManager.execute(request, "authorization-" + token, DurationInMillis.ONE_DAY, hasAuthorization); } else if ("single".equals(type.getReqType())) { button = (Button) LayoutInflater.from(THIS).inflate(R.layout.button_visa, null); button.setText(type.getLabel() + " - " + service.getPrice() + " " + service.getSign()); OnPaypalClick onPaypalClick = new OnPaypalClick(); onPaypalClick.setCurrency(service.getCurrency()); onPaypalClick.setPrice(service.getPrice()); onPaypalClick.setTax(service.getTaxRate()); onPaypalClick.setRepo(repo); try { JSONObject sku_details = new JSONObject(detailsList.get(0)); onPaypalClick.setDescription(sku_details.getString("title") + " - " + sku_details.getString("description")); } catch (Exception e) { e.printStackTrace(); onPaypalClick.setDescription(getString(R.string.no_description)); } button.setOnClickListener(onPaypalClick); paymentMethodsLayout.addView(button); if(response.getPayment_services().size() == 1 && service.getTypes().size() == 1){ onPaypalClick.onClick(null); } } } break; case UNITEL_CODE: caseUNITEL(service,paymentMethodsLayout); break; } } } if(!detailsList.isEmpty()) Log.d("AptoideSkudetailsForPurchase", "SkuDetails: " + detailsList.get(0)); //if(detailsJson != null) { try { findViewById(R.id.progress).setVisibility(View.GONE); findViewById(R.id.content).setVisibility(View.VISIBLE); JSONObject sku_details = new JSONObject(detailsList.get(0)); aptoideProductId = response.getMetadata().getId(); ((TextView) findViewById(R.id.title)).setText(sku_details.getString("title")); ((TextView) findViewById(R.id.price)).setText(sku_details.getString("price")); Glide.with(IABPurchaseActivity.this).load(response.getMetadata().getIcon()).into((ImageView) findViewById(R.id.icon)); ((TextView) findViewById(R.id.app_purchase_description)).setText(sku_details.getString("description")); } catch (Exception e) { e.printStackTrace(); Intent intent = new Intent(); intent.putExtra(BillingBinder.RESPONSE_CODE, BillingBinder.RESULT_ERROR); setResult(RESULT_OK, intent); finish(); } } } }); } }).start(); } @Override protected void processPaymentConfirmation(final ProofOfPayment confirmation) { final BasePurchaseStatusRequest purchaseStatus = BuildPurchaseStatusRequest(confirmation); purchaseStatus.setDeveloperPayload(developerPayload); purchaseStatus.setApiVersion(String.valueOf(apiVersion)); DialogFragment df = new ProgressDialogFragment(); df.show(getSupportFragmentManager(), "pleaseWaitDialog"); df.setCancelable(false); spiceManager.execute(purchaseStatus, new PurchaseRequestListener() { @Override public void onRequestFailure(SpiceException spiceException) { AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); Toast.makeText(Aptoide.getContext(), R.string.error_occured_retry_later, Toast.LENGTH_LONG).show(); Intent i = buildIntentForAlarm(confirmation, "iab"); i.putExtra("apiVersion", apiVersion); i.putExtra("developerPayload", developerPayload); PendingIntent intent = PendingIntent.getBroadcast(getApplicationContext(), 1, i, PendingIntent.FLAG_UPDATE_CURRENT); manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 60000, 60000, intent); dismissAllowingStateLoss(); } }); } @Override protected BasePurchaseStatusRequest BuildPurchaseStatusRequest() { return new IabPurchaseStatusRequest(); } }