Skip to content

Instantly share code, notes, and snippets.

@webserveis
Created December 5, 2016 11:22
Show Gist options
  • Save webserveis/1a0ac26f22e5f30fed99c0e3718ba038 to your computer and use it in GitHub Desktop.
Save webserveis/1a0ac26f22e5f30fed99c0e3718ba038 to your computer and use it in GitHub Desktop.
Basic system bill inapp
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Base64;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
import com.webserveis.app.splitpaywear.util.IabBroadcastReceiver;
import com.webserveis.app.splitpaywear.util.IabHelper;
import com.webserveis.app.splitpaywear.util.IabResult;
import com.webserveis.app.splitpaywear.util.Inventory;
import com.webserveis.app.splitpaywear.util.Purchase;
import com.webserveis.app.splitpaywear.util.ThemeUtils;
/*
https://gist.github.com/gabrielemariotti/117b05aad4db251f7534
http://stackoverflow.com/questions/30050299/how-to-launch-android-wear-activity-from-mobile
Bill inapp
Facturación integrada
https://developer.android.com/google/play/billing/index.html
https://www.dexa-dev.com/android-in-app-billing-empezamos-con-el-codigo-iv/
https://inducesmile.com/android/android-in-app-billing-v3-purchase-using-serviceconnection-example-tutorial/
http://www.techotopia.com/index.php/An_Android_Studio_Google_Play_In-app_Billing_Tutorial#Installing_the_Google_Play_Billing_Library
http://stackoverflow.com/questions/8735931/android-in-app-billing-tutorial => for multiple activities
Seguridad y diseño
https://developer.android.com/google/play/billing/billing_best_practices.html#key
Random string payload
http://stackoverflow.com/questions/18613520/what-should-be-the-developer-payload-in-android-in-app-billing-v3-api
*/
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
IabBroadcastReceiver.IabBroadcastListener {
private GoogleApiClient mGoogleApiClient;
private String TAG = MainActivity.class.getSimpleName();
private IabHelper mHelper;
private IabBroadcastReceiver mBroadcastReceiver;
private IabHelper.QueryInventoryFinishedListener mGotInventoryListener;
// Does the user have the premium upgrade?
boolean mIsPremium = false;
static final String SKU_PREMIUM = "premium";
//static final String SKU_PREMIUM = "android.test.purchased";
//static final String SKU_PREMIUM = "android.test.canceled";
//static final String SKU_PREMIUM = "android.test.refunded";
//static final String SKU_PREMIUM = "android.test.item_unavailable";
// (arbitrary) request code for the purchase flow
static final int RC_REQUEST = 10001;
private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
Intent serviceIntent =
new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
*/
/**
* IN APP BILLING IMPLEMENTATION
*/
//String base64EncodedPublicKey = "YOU_APP_PUBLIC_KEY";
mHelper = new IabHelper(this, base64EncodedPublicKey);
// enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(true);
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
@Override
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
Log.e(TAG, "In-app Billing setup failed: " + result);
} else {
Log.d(TAG, "In-app Billing is set up OK");
}
if (mHelper == null) return;
mBroadcastReceiver = new IabBroadcastReceiver((IabBroadcastReceiver.IabBroadcastListener) MainActivity.this);
IntentFilter broadcastFilter = new IntentFilter(IabBroadcastReceiver.ACTION);
registerReceiver(mBroadcastReceiver, broadcastFilter);
// IAB is fully set up. Now, let's get an inventory of stuff we own.
Log.d(TAG, "Setup successful. Querying inventory.");
try {
mHelper.queryInventoryAsync(mGotInventoryListener);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error querying inventory. Another async operation in progress.");
}
}
});
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.");
// Do we have the premium upgrade?
Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
Log.d("PREMIUM =","User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
alert("User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
// Callback for when a purchase is finished cuando se ha establecido el pago
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()) {
if (result.getResponse() == 7) {
complain("Ya tiene el producto ");
} else {
complain("Error purchasing: " + result);
}
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
return;
}
Log.w(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_PREMIUM)) {
// bought the premium upgrade!
Log.w(TAG, "Purchase is premium upgrade. Congratulating user.");
alert("Thank you for upgrading to premium!");
mIsPremium = true;
}
}
};
Button myButton1 = (Button) findViewById(R.id.btn_getpremium);
if (myButton1 != null) {
myButton1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String payload = "mypurchasetoken";
try {
mHelper.launchPurchaseFlow(MainActivity.this, SKU_PREMIUM, RC_REQUEST,
mPurchaseFinishedListener, payload);
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
}
}
});
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//toolbar.setPopupTheme(R.style.AppThemeGreen_PopupOverlay);
final TextView myTextView = (TextView) findViewById(R.id.textView);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
int intColor = ThemeUtils.getColor(MainActivity.this, R.color.colorAccent);
Log.d(TAG, "colors.xml colorAccent: " + intColor);
String hexColor = ThemeUtils.colorIntToHex(intColor);
Log.d(TAG, "colors.xml colorAccent: " + hexColor);
myTextView.setTextColor(intColor);
intColor = ThemeUtils.getThemeAttribute(MainActivity.this, R.attr.colorAccent);
intColor = ThemeUtils.getThemeAttribute(MainActivity.this, android.R.attr.textColorSecondary);
hexColor = ThemeUtils.colorIntToHex(intColor);
Log.d(TAG, "textColorPrimary Int: " + intColor);
Log.d(TAG, "textColorPrimary: " + hexColor);
myTextView.setTextColor(Color.parseColor(hexColor));
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onConnected(Bundle bundle) {
Log.d("GoogleApi", "onConnected: " + bundle);
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
@Override
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
for (Node node : getConnectedNodesResult.getNodes()) {
Log.d(TAG, "onResult: " + node.getDisplayName());
//sendMessage(node.getId());
}
}
});
}
@Override
public void onConnectionSuspended(int i) {
Log.d("GoogleApi", "onConnectionSuspended: " + i);
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.d("GoogleApi", "onConnectionFailed: " + connectionResult);
}
@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)) {
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
@Override
public void onDestroy() {
super.onDestroy();
// very important:
if (mBroadcastReceiver != null) {
unregisterReceiver(mBroadcastReceiver);
}
if (mHelper != null) {
mHelper.disposeWhenFinished();
mHelper = null;
}
}
public static String xorEncrypt(String input, String key) {
byte[] inputBytes = input.getBytes();
int inputSize = inputBytes.length;
byte[] keyBytes = key.getBytes();
int keySize = keyBytes.length - 1;
byte[] outBytes = new byte[inputSize];
for (int i = 0; i < inputSize; i++) {
outBytes[i] = (byte) (inputBytes[i] ^ keyBytes[i % keySize]);
}
return new String(Base64.encode(outBytes, Base64.DEFAULT));
}
public static String xorDecrypt(String input, String key) {
byte[] inputBytes = Base64.decode(input, Base64.DEFAULT);
int inputSize = inputBytes.length;
byte[] keyBytes = key.getBytes();
int keySize = keyBytes.length - 1;
byte[] outBytes = new byte[inputSize];
for (int i = 0; i < inputSize; i++) {
outBytes[i] = (byte) (inputBytes[i] ^ keyBytes[i % keySize]);
}
return new String(outBytes);
}
void complain(String message) {
Log.e(TAG, "**** TrivialDrive Error: " + message);
alert("Error: " + message);
}
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();
}
@Override
public void receivedBroadcast() {
// Received a broadcast notification that the inventory of items has changed
Log.d(TAG, "Received broadcast notification. Querying inventory.");
try {
mHelper.queryInventoryAsync(mGotInventoryListener);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error querying inventory. Another async operation in progress.");
}
}
public boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment