package com.aptoide.amethyst.openiab; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v7.app.ActionBarActivity; import android.telephony.TelephonyManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; import com.aptoide.amethyst.R; import com.aptoide.amethyst.analytics.Analytics; import com.aptoide.amethyst.dialogs.ProgressDialogFragment; import com.aptoide.dataprovider.AptoideSpiceHttpService; import com.aptoide.models.PaymentServices; import com.octo.android.robospice.SpiceManager; 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.octo.android.robospice.retry.RetryPolicy; import com.paypal.android.sdk.payments.PayPalAuthorization; import com.paypal.android.sdk.payments.PayPalConfiguration; import com.paypal.android.sdk.payments.PayPalFuturePaymentActivity; import com.paypal.android.sdk.payments.PayPalPayment; import com.paypal.android.sdk.payments.PayPalService; import com.paypal.android.sdk.payments.PaymentActivity; import com.paypal.android.sdk.payments.PaymentConfirmation; import com.paypal.android.sdk.payments.ProofOfPayment; import org.json.JSONException; import org.onepf.oms.BillingBinder; import java.math.BigDecimal; import java.text.DecimalFormat; import java.util.HashMap; import com.aptoide.amethyst.openiab.webservices.BasePurchaseStatusRequest; import com.aptoide.amethyst.openiab.webservices.IabPurchaseStatusRequest; import com.aptoide.amethyst.openiab.webservices.PaidAppPurchaseStatusRequest; import com.aptoide.amethyst.openiab.webservices.PayProductRequestBase; import com.aptoide.amethyst.openiab.webservices.PayProductRequestPayPal; import com.aptoide.amethyst.openiab.webservices.PayProductRequestUnitel; import com.aptoide.amethyst.openiab.webservices.PaypalPurchaseAuthorizationRequest; import com.aptoide.amethyst.openiab.webservices.json.IabPurchaseStatusJson; import com.aptoide.amethyst.openiab.webservices.json.IabSimpleResponseJson; public abstract class BasePurchaseActivity extends ActionBarActivity implements Callback { private static final String TAG = "paymentExample"; static HashMap<String, Integer> servicesList = new HashMap<String, Integer>(); protected static final String PAYPAL_NAME = "paypal"; protected static final String UNITEL_NAME = "unitel"; protected static final String FORTUMO_NAME = "fortumo"; protected static final int PAYPAL_CODE = 1; protected static final int UNITEL_CODE = 2; protected static final int FORTUMO_CODE = 3; private static final String CONFIG_ENVIRONMENT = PayPalConfiguration.ENVIRONMENT_PRODUCTION; // note that these credentials will differ between live & sandbox environments. private static final String CONFIG_CLIENT_ID = "AW47wxAycZoTcXd5KxcJPujXWwImTLi-GNe3XvUUwFavOw8Nq4ZnlDT1SZIY"; //private static final String CONFIG_CLIENT_ID = "AQ7o2RBHX3UxiM3xhHccETYWVVLLU0nD7GXxsmQg2MhRajAZztqHeidrPgqr"; private static final int REQUEST_CODE_PAYMENT = 1; private static final int REQUEST_CODE_FUTURE_PAYMENT = 2; private static PayPalConfiguration config; static { servicesList.put(PAYPAL_NAME, PAYPAL_CODE); servicesList.put(UNITEL_NAME, UNITEL_CODE); servicesList.put(FORTUMO_NAME, FORTUMO_CODE); config = new PayPalConfiguration() .environment(CONFIG_ENVIRONMENT) .clientId(CONFIG_CLIENT_ID) // The following are only used in PayPalFuturePaymentActivity. .merchantName("Aptoide"); } protected String packageName; AsyncTask<Void, Void, Bundle> execute; protected int aptoideProductId; protected SpiceManager spiceManager = new SpiceManager(AptoideSpiceHttpService.class); protected String simcc; protected String repo; protected ValuesToVerify valuesToVerify; private boolean alreadyRegistered = false; //protected boolean isBound; protected String token; @Override protected void onStart() { super.onStart(); spiceManager.start(this); // FlurryAgent.onStartSession(this, getResources().getString(R.string.FLURRY_KEY)); } @Override protected void onStop() { super.onStop(); spiceManager.shouldStop(); // FlurryAgent.onEndSession(this); } public class HasAuthorization implements RequestListener<IabSimpleResponseJson> { private String currency; private double price; private double tax; private Button button; public void setCurrency(String currency) { this.currency = currency; } public void setPrice(double price) { this.price = price; } public void setTax(double tax) { this.tax = tax; } public HasAuthorization(Button button) { this.button = button; } @Override public void onRequestFailure(SpiceException spiceException) { OnPaypalFutureClick onPaypalFutureClick = new OnPaypalFutureClick(); onPaypalFutureClick.setProductId(String.valueOf(aptoideProductId)); button.setOnClickListener(onPaypalFutureClick); } @Override public void onRequestSuccess(IabSimpleResponseJson iabPurchaseStatusJson) { OnPaypalFutureClick onPaypalFutureClick = new OnPaypalFutureClick(); onPaypalFutureClick.setCurrency(this.currency); onPaypalFutureClick.setPrice(this.price); onPaypalFutureClick.setTax(this.tax); alreadyRegistered = iabPurchaseStatusJson.getStatus().equals("OK"); onPaypalFutureClick.setProductId(String.valueOf(aptoideProductId)); button.setOnClickListener(onPaypalFutureClick); } } protected void requestsetExtra(PayProductRequestBase pprb){ return; } @Override public void onClick(int payType, String imsi, String price, String currency) { DialogFragment df = new ProgressDialogFragment(); df.setCancelable(false); df.show(getSupportFragmentManager(), "pleaseWaitDialog"); PayProductRequestUnitel requestUnitel = new PayProductRequestUnitel(); requestUnitel.setProductId(String.valueOf(aptoideProductId)); requestUnitel.setPayType(String.valueOf(payType)); requestUnitel.setToken(token); requestUnitel.setImsi(imsi); requestUnitel.setPrice(price); requestUnitel.setCurrency(currency); requestUnitel.setRepo(repo); requestsetExtra(requestUnitel); requestUnitel.setRetryPolicy(noRetryPolicy); spiceManager.execute(requestUnitel, new PurchaseRequestListener()); } @Override public void onCancel() { } public class ValuesToVerify { public double tax; public double price; public String currency; public String repo; } public class OnPaypalClick implements View.OnClickListener { private String description; private double price; private String currency; private double tax; private String repo; public void setPrice(double price) { this.price = price; } public void setCurrency(String currency) { this.currency = currency; } public void setDescription(String description) { this.description = description; } @Override public void onClick(View view) { valuesToVerify = new ValuesToVerify(); valuesToVerify.currency = this.currency; valuesToVerify.price = this.price; valuesToVerify.tax = this.tax; valuesToVerify.repo = this.repo; PayPalPayment thingToBuy = new PayPalPayment(new BigDecimal(price), currency, description, PayPalPayment.PAYMENT_INTENT_SALE); Intent intent = new Intent(BasePurchaseActivity.this, PaymentActivity.class); intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy); startActivityForResult(intent, REQUEST_CODE_PAYMENT); // FlurryAgent.logEvent("Purchase_Page_Clicked_On_Paypal_Button"); } public void setTax(double tax) { this.tax = tax; } public double getTax() { return tax; } public void setRepo(String repo) { this.repo = repo; } } public class OnPaypalFutureClick implements View.OnClickListener { private String productId; private String currency; private double price; private double tax; public void setProductId(String price) { this.productId = price; } @Override public void onClick(View view) { valuesToVerify = new ValuesToVerify(); valuesToVerify.currency = this.currency; valuesToVerify.price = this.price; valuesToVerify.tax = this.tax; valuesToVerify.repo = repo; if (alreadyRegistered) { final String correlationId = PayPalConfiguration.getApplicationCorrelationId(BasePurchaseActivity.this); PayProductRequestPayPal request = new PayProductRequestPayPal(); request.setToken(token); request.setRepo(repo); request.setProductId(productId); request.setPrice(String.valueOf(price)); request.setCurrency(currency); if(simcc!=null && simcc.length()>0){ request.setSimCountryCode(simcc); } request.setCorrelationId(correlationId); request.setRetryPolicy(noRetryPolicy); requestsetExtra(request); DialogFragment df = new ProgressDialogFragment(); df.show(getSupportFragmentManager(), "pleaseWaitDialog"); df.setCancelable(false); spiceManager.execute(request, new PurchaseRequestListener()); } else { Intent ppIntent = new Intent(BasePurchaseActivity.this, PayPalFuturePaymentActivity.class); startActivityForResult(ppIntent, REQUEST_CODE_FUTURE_PAYMENT); spiceManager.removeDataFromCache(IabSimpleResponseJson.class, "authorization-" + token); } } public void setCurrency(String currency) { this.currency = currency; } public String getCurrency() { return currency; } public void setPrice(double price) { this.price = price; } public double getPrice() { return price; } public void setTax(double tax) { this.tax = tax; } public double getTax() { return tax; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(Build.VERSION.SDK_INT < 8){ Toast.makeText(this, getString(R.string.error_SYS_Billing), Toast.LENGTH_LONG).show(); return; } Intent paypalIntent = new Intent(this, PayPalService.class); paypalIntent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config); startService(paypalIntent); final Intent intent = getIntent(); packageName = intent.getStringExtra("packageName"); token = intent.getStringExtra("token"); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(resultCode, resultCode, data); Log.d("pois","BasePurchaseActivity onActivityResult"); switch (requestCode){ case REQUEST_CODE_PAYMENT: if (resultCode == Activity.RESULT_OK) { PaymentConfirmation confirm = data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION); if (confirm != null) { try { Log.i(TAG, confirm.toJSONObject().toString(4)); Log.i(TAG, confirm.getProofOfPayment().toJSONObject().toString(4)); Log.i(TAG, confirm.getPayment().toJSONObject().toString(4)); /** * TODO: send 'confirm' (and possibly confirm.getPayment() to your server for verification * or consent completion. * See https://developer.paypal.com/webapps/developer/docs/integration/mobile/verify-mobile-payment/ * for more details. * * For sample mobile backend interactions, see * https://github.com/paypal/rest-api-sdk-python/tree/master/samples/mobile_backend */ processPaymentConfirmation(confirm.getProofOfPayment()); Analytics.LTV.purchasedApp(packageName, parsePaypalPayment(confirm.getPayment().toString())); } catch (JSONException e) { Log.e(TAG, "an extremely unlikely failure occurred: ", e); } } } else if (resultCode == Activity.RESULT_CANCELED) { Log.i(TAG, "The user canceled."); } else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) { Toast.makeText(BasePurchaseActivity.this, R.string.error_occured, Toast.LENGTH_LONG).show(); Log.i(TAG, "An invalid Payment or PayPalConfiguration was submitted. Please see the docs."); } break; case REQUEST_CODE_FUTURE_PAYMENT: if (resultCode == Activity.RESULT_OK) { PayPalAuthorization auth = data.getParcelableExtra(PayPalFuturePaymentActivity.EXTRA_RESULT_AUTHORIZATION); if (auth != null) { try { Log.i("FuturePaymentExample", auth.toJSONObject().toString(4)); String authorization_code = auth.getAuthorizationCode(); Log.i("FuturePaymentExample", authorization_code); sendAuthorizationToServer(auth); } catch (JSONException e) { Log.e("FuturePaymentExample", "an extremely unlikely failure occurred: ", e); } } } else if (resultCode == Activity.RESULT_CANCELED) { Log.i("FuturePaymentExample", "The user canceled."); Log.i("FuturePaymentExample", "Probably the attempt to previously start the PayPalService had an invalid PayPalConfiguration." + " Please see the docs."); } else { Toast.makeText(BasePurchaseActivity.this, R.string.error_occured, Toast.LENGTH_LONG).show(); } break; } } private void sendAuthorizationToServer(final PayPalAuthorization authorization) { /** * TODO: Send the authorization response to your server, where it can * exchange the authorization code for OAuth access and refresh tokens. * * Your server must then store these tokens, so that your server code * can execute payments for this user in the future. * * A more complete example that includes the required app-server to * PayPal-server integration is available from * https://github.com/paypal/rest-api-sdk-python/tree/master/samples/mobile_backend */ PaypalPurchaseAuthorizationRequest request = new PaypalPurchaseAuthorizationRequest(); request.setAuthToken(authorization.getAuthorizationCode()); request.setToken(token); DialogFragment df = new ProgressDialogFragment(); df.setCancelable(false); df.show(getSupportFragmentManager(), "pleaseWaitDialog"); spiceManager.execute(request, new RequestListener<IabSimpleResponseJson>() { @Override public void onRequestFailure(SpiceException spiceException) { Toast.makeText(BasePurchaseActivity.this, R.string.failed_auth_code, Toast.LENGTH_LONG).show(); dismissAllowingStateLoss(); } @Override public void onRequestSuccess(IabSimpleResponseJson iabPurchaseStatusJson) { String correlationId = PayPalConfiguration.getApplicationCorrelationId(BasePurchaseActivity.this); PayProductRequestPayPal request = new PayProductRequestPayPal(); request.setToken(token); if(simcc!=null && simcc.length()>0){ request.setSimCountryCode(simcc); } request.setPrice(String.valueOf(valuesToVerify.price)); request.setCurrency(valuesToVerify.currency); request.setProductId(String.valueOf(aptoideProductId)); request.setCorrelationId(correlationId); request.setRetryPolicy(noRetryPolicy); requestsetExtra(request); if("OK".equals(iabPurchaseStatusJson.getStatus())) { spiceManager.execute(request, new PurchaseRequestListener()); }else{ Toast.makeText(BasePurchaseActivity.this, R.string.error_occured_paying, Toast.LENGTH_LONG).show(); dismissAllowingStateLoss(); } } }); } RetryPolicy noRetryPolicy = new RetryPolicy() { @Override public int getRetryCount() { return 0; } @Override public void retry(SpiceException e) { } @Override public long getDelayBeforeRetry() { return 0; } }; protected abstract void processPaymentConfirmation(final ProofOfPayment confirmation); protected Intent buildIntentForAlarm(ProofOfPayment confirmation, String paymenType){ Intent i = new Intent("PAYPAL_PAYMENT"); i.putExtra("token", token); i.putExtra("aptoideProductId", aptoideProductId); i.putExtra("tax", valuesToVerify.tax); i.putExtra("price", valuesToVerify.price); i.putExtra("currency", valuesToVerify.currency); i.putExtra("paymentId", confirmation.getPaymentId()); i.putExtra("paymentType", paymenType); if(simcc!=null)i.putExtra("simcc", simcc); return i; } protected abstract BasePurchaseStatusRequest BuildPurchaseStatusRequest(); protected BasePurchaseStatusRequest BuildPurchaseStatusRequest(ProofOfPayment confirmation){ final BasePurchaseStatusRequest purchaseStatus = BuildPurchaseStatusRequest(); purchaseStatus.setToken(token); purchaseStatus.setProductId(aptoideProductId); purchaseStatus.setPayType(1); purchaseStatus.setPayKey(confirmation.getPaymentId()); purchaseStatus.setTaxRate(valuesToVerify.tax); purchaseStatus.setPrice(valuesToVerify.price); purchaseStatus.setCurrency(valuesToVerify.currency); purchaseStatus.setRepo(valuesToVerify.repo); if(simcc!=null)purchaseStatus.setSimcc(simcc); return purchaseStatus; } @Override protected void onDestroy() { stopService(new Intent(this, PayPalService.class)); super.onDestroy(); if (execute != null && !execute.isCancelled()) { execute.cancel(false); } } protected void dismissAllowingStateLoss(){ DialogFragment pd = (DialogFragment) getSupportFragmentManager().findFragmentByTag("pleaseWaitDialog"); if (pd != null) { pd.dismissAllowingStateLoss(); } } public class PurchaseRequestListener implements RequestListener<IabPurchaseStatusJson>{ @Override public void onRequestFailure(SpiceException spiceException) { Toast.makeText(BasePurchaseActivity.this, R.string.error_occured_paying, Toast.LENGTH_LONG).show(); dismissAllowingStateLoss(); } @Override public void onRequestSuccess(IabPurchaseStatusJson iabPurchaseStatusJson) { Intent intent = new Intent(); dismissAllowingStateLoss(); if (iabPurchaseStatusJson != null) { if ("OK".equals(iabPurchaseStatusJson.getStatus())) { if (makeExtraTestsOnPurchaseOk(iabPurchaseStatusJson)) { intent.putExtra(BillingBinder.RESPONSE_CODE, BillingBinder.RESULT_DEVELOPER_ERROR); } if ("COMPLETED".equals(iabPurchaseStatusJson.getPublisherResponse().getData().get(0).getPurchaseState())) { intent.putExtra(BillingBinder.INAPP_PURCHASE_DATA, iabPurchaseStatusJson.getPublisherResponse().getData().get(0).getJson()); intent.putExtra(BillingBinder.INAPP_DATA_SIGNATURE, iabPurchaseStatusJson.getPublisherResponse().getSignature().get(0)); intent.putExtra(BillingBinder.RESPONSE_CODE, BillingBinder.RESULT_OK); } else { intent.putExtra(BillingBinder.RESPONSE_CODE, BillingBinder.RESULT_ERROR); Toast.makeText(BasePurchaseActivity.this, getString(R.string.billing_result) + iabPurchaseStatusJson.getPublisherResponse().getData().get(0).getPurchaseState(), Toast.LENGTH_LONG).show(); } } } else { intent.putExtra(BillingBinder.RESPONSE_CODE, BillingBinder.RESULT_ERROR); } Log.d("pois", "PurchaseRequestListener finish setResult Result ok."); setResult(RESULT_OK, intent); finish(); } } protected boolean makeExtraTestsOnPurchaseOk(IabPurchaseStatusJson iabPurchaseStatusJson){ return false; } private void telephonyPayment(PaymentServices service,LinearLayout paymentMethodsLayout,int buttonResource,View.OnClickListener onClick){ Button button; final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); if(telephonyManager!=null && telephonyManager.getSimState()== TelephonyManager.SIM_STATE_READY){ for (PaymentServices.PaymentType type : service.getTypes()) { button = (Button) LayoutInflater.from(this).inflate(buttonResource, null); if (button != null) { button.setText(type.getLabel() + " - " + service.getPrice() + " " + service.getSign()); paymentMethodsLayout.addView(button); button.setOnClickListener(onClick); } } } } protected void caseUNITEL(PaymentServices service,LinearLayout paymentMethodsLayout){ final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); final DecimalFormat df = new DecimalFormat("######.#"); telephonyPayment(service,paymentMethodsLayout, R.layout.button_unitel,new UnitelPurchaseListener(getSupportFragmentManager(), String.valueOf(service.getPrice()), telephonyManager.getSimOperatorName(), service.getName(), service.getId(), telephonyManager.getSubscriberId(), service.getCurrency(), df.format(service.getPrice()))); } private double parsePaypalPayment(String str) { int start = str.indexOf('$') + 1; int end = str.indexOf(' ', start) - 1; return Double.valueOf(str.substring(start, end)) * 100; } }