package net.rdrei.android.scdl2.ui;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.MenuItem;
import com.android.vending.billing.IabHelper;
import com.android.vending.billing.IabHelper.OnIabPurchaseFinishedListener;
import com.android.vending.billing.IabHelper.OnIabSetupFinishedListener;
import com.android.vending.billing.IabHelper.QueryInventoryFinishedListener;
import com.android.vending.billing.IabResult;
import com.android.vending.billing.Inventory;
import com.android.vending.billing.Purchase;
import com.crashlytics.android.Crashlytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import com.google.inject.Inject;
import com.squareup.otto.Bus;
import com.squareup.otto.Produce;
import com.squareup.otto.Subscribe;
import net.rdrei.android.scdl2.ApplicationPreferences;
import net.rdrei.android.scdl2.R;
import roboguice.activity.RoboFragmentActivity;
import roboguice.util.Ln;
/**
* This activity loads the appropriate fragments based on whether the user has done a purchase yet
* or not. It will also handle the payment processing via messages from the corresponding
* fragments.
*
* @author pascal
*/
public class BuyAdFreeActivity extends RoboFragmentActivity implements OnIabSetupFinishedListener, QueryInventoryFinishedListener, OnIabPurchaseFinishedListener {
public static enum PaymentStatus {
BOUGHT, NOT_BOUGHT, UNKNOWN
}
public static enum IabStatus {
ENABLED, DISABLED, UNKNOWN
}
private static final String ANALYTICS_TAG = "BUY_ADFREE";
/**
* Request code to differentiate between different items.
*/
private static final int ADFREE_REQUEST_CODE = 0;
/**
* SKU used in the developer console to identify the item.
*/
public static final String ADFREE_SKU = "adfree";
@Inject
private ApplicationPreferences mPreferences;
@Inject
private ActionBar mActionBar;
@Inject
private Tracker mTracker;
@Inject
private IabHelper mIabHelper;
@Inject
private Bus mBus;
@Inject
private FragmentManager mFragmentManager;
private Fragment mContentFragment;
private PaymentStatus mBought;
/**
* Keeps track of whether the device supports IAB. Listen to {@link IabSetupFinishedEvent} to be
* informed of changes.
*/
private IabStatus mIabSupported;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.buy_ad_free);
mActionBar.setDisplayHomeAsUpEnabled(true);
mIabHelper.startSetup(this);
mBought = PaymentStatus.UNKNOWN;
mIabSupported = IabStatus.UNKNOWN;
if (savedInstanceState == null) {
loadFragments();
}
}
@Override
protected void onStart() {
super.onStart();
trackFunnelEvent("START");
mBus.register(this);
Ln.d("mBus @ activity: %s", System.identityHashCode(mBus));
}
@Override
protected void onResume() {
super.onResume();
if (mBought == PaymentStatus.BOUGHT) {
trackFunnelEvent("BOUGHT");
replaceWithThanksFragment();
} else {
trackFunnelEvent("RESUME");
}
}
@Override
protected void onStop() {
super.onStop();
trackFunnelEvent("EXIT");
mBus.unregister(this);
}
private void loadFragments() {
final FragmentTransaction transaction = mFragmentManager.beginTransaction();
if (mPreferences.isAdFree()) {
mContentFragment = BuyAdFreeThanksFragment.newInstance();
} else {
mContentFragment = BuyAdFreeTeaserFragment.newInstance();
}
transaction.add(R.id.main_layout, mContentFragment).commit();
}
private void replaceWithThanksFragment() {
if (mContentFragment instanceof BuyAdFreeTeaserFragment) {
final Fragment newFragment = BuyAdFreeThanksFragment.newInstance();
mFragmentManager.beginTransaction()
.remove(mContentFragment)
.add(R.id.main_layout, newFragment)
.commitAllowingStateLoss();
mContentFragment = newFragment;
}
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (item.getItemId() == android.R.id.home) {
final Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onIabSetupFinished(final IabResult result) {
Ln.d("onIabSetupFinished: %s", result);
if (result == null) {
trackFunnelError("onIabSetupFinished: null result");
finishWithSorry();
return;
}
mIabSupported = result.isSuccess() ? IabStatus.ENABLED : IabStatus.DISABLED;
mBus.post(new IabSetupFinishedEvent(mIabSupported));
if (result.isSuccess()) {
try {
mIabHelper.queryInventoryAsync(this);
} catch (IllegalStateException e) {
Crashlytics.logException(e);
finishWithSorry();
}
} else {
Ln.w("Can't connect to IAB: %s", result);
trackFunnelError("onIabFinished: connection error - " + result.toString());
}
}
private void finishWithSorry() {
new AlertDialog.Builder(this).setMessage(
getString(R.string.error_iab_connect_message))
.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(final DialogInterface arg0, final int arg1) {
finish();
}
})
.create()
.show();
}
@Override
public void onQueryInventoryFinished(final IabResult result, final Inventory inv) {
Ln.d("onQueryInventoryFinished: %s", result);
if (result.isFailure()) {
trackFunnelError(String.format("onQueryInventoryFinished: %s", result));
Ln.w("Failed to retrieve inventory!");
return;
}
trackFunnelEvent("INVENTORY");
final boolean hasItem = inv.hasPurchase(ADFREE_SKU);
final PurchaseStateChangeEvent event = new PurchaseStateChangeEvent(
hasItem ? PaymentStatus.BOUGHT : PaymentStatus.NOT_BOUGHT);
mBus.post(event);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mIabHelper != null) {
mIabHelper.dispose();
mIabHelper = null;
}
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode,
final Intent data) {
Ln.d("onActivityResult(" + requestCode + "," + resultCode + "," + data);
// Closure-style callback passing to avoid code duplication.
final Runnable handleResult = new Runnable() {
@Override
public void run() {
// Pass on the activity result to the helper for handling
if (!mIabHelper.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...
BuyAdFreeActivity.super.onActivityResult(requestCode, resultCode, data);
}
}
};
if (mIabHelper.isSetupDone()) {
handleResult.run();
} else {
mIabHelper.startSetup(new OnIabSetupFinishedListener() {
@Override
public void onIabSetupFinished(final IabResult result) {
if (result.isSuccess()) {
handleResult.run();
} else {
trackFunnelError(String.format("onActivityResult: %s", result));
}
}
});
}
}
@Subscribe
public void onPurchaseRequested(final PurchaseAdfreeRequestEvent event) {
trackFunnelEvent("PURCHASE_REQUEST");
mIabHelper.launchPurchaseFlow(this, ADFREE_SKU, ADFREE_REQUEST_CODE, this);
}
@Subscribe
public void onPurchaseStateChanged(final PurchaseStateChangeEvent event) {
Ln.i("Saving purchase state as %s.", event.purchased);
if (event.purchased == PaymentStatus.BOUGHT) {
mPreferences.setAdFree(true);
trackFunnelEvent("SUCCESS");
mBought = PaymentStatus.BOUGHT;
replaceWithThanksFragment();
}
}
@Produce
public IabSetupFinishedEvent produceIabSetupFinishedEvent() {
return new IabSetupFinishedEvent(mIabSupported);
}
@Produce
public PurchaseStateChangeEvent producePurchaseStateChangeEvent() {
return new PurchaseStateChangeEvent(mBought);
}
@Override
public void onIabPurchaseFinished(final IabResult result, final Purchase info) {
Ln.d("onIabPurchaseFinished: %s", result);
final boolean success = result.isSuccess() && info.getSku().equals(ADFREE_SKU);
mBus.post(new PurchaseAdfreeFinishedEvent(success));
if (success) {
mBus.post(new PurchaseStateChangeEvent(PaymentStatus.BOUGHT));
} else if (result.getResponse() == IabHelper.BILLING_RESPONSE_RESULT_USER_CANCELED) {
trackFunnelEvent("CANCEL");
} else {
trackFunnelError(String.format("onIabPurchaseFinished: %s", result));
}
}
public static final class IabSetupFinishedEvent {
public final IabStatus enabled;
public IabSetupFinishedEvent(final IabStatus enabled) {
this.enabled = enabled;
}
}
public static final class PurchaseStateChangeEvent {
public final PaymentStatus purchased;
public PurchaseStateChangeEvent(final PaymentStatus purchased) {
super();
this.purchased = purchased;
}
}
public static final class PurchaseAdfreeRequestEvent {
}
public static final class PurchaseAdfreeFinishedEvent {
final public boolean success;
public PurchaseAdfreeFinishedEvent(final boolean success) {
super();
this.success = success;
}
}
private void trackFunnelEvent(final String name) {
mTracker.send(
new HitBuilders.EventBuilder()
.setCategory(ANALYTICS_TAG)
.setAction(name)
.build()
);
}
private void trackFunnelError(final String message) {
mTracker.send(
new HitBuilders.ExceptionBuilder().setDescription(message).setFatal(false).build()
);
}
}