package co.smartreceipts.android.ad;
import android.app.Activity;
import android.content.res.Resources;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.NativeExpressAdView;
import java.lang.ref.WeakReference;
import java.util.Random;
import javax.inject.Inject;
import co.smartreceipts.android.R;
import co.smartreceipts.android.analytics.Analytics;
import co.smartreceipts.android.analytics.events.Events;
import co.smartreceipts.android.di.scopes.ApplicationScope;
import co.smartreceipts.android.persistence.SharedPreferenceDefinitions;
import co.smartreceipts.android.purchases.PurchaseEventsListener;
import co.smartreceipts.android.purchases.PurchaseManager;
import co.smartreceipts.android.purchases.model.InAppPurchase;
import co.smartreceipts.android.purchases.source.PurchaseSource;
import co.smartreceipts.android.purchases.wallet.PurchaseWallet;
import co.smartreceipts.android.utils.log.Logger;
@ApplicationScope
public class FreeAdManager implements AdManager, PurchaseEventsListener {
private static final int RANDOM_MAX = 100;
private static final int UPSELL_FREQUENCY = 1; // Out of 100
//Preference Identifiers - SubClasses Only
private static final String AD_PREFERENECES = SharedPreferenceDefinitions.SubclassAds.toString();
private static final String SHOW_AD = "pref1";
private final PurchaseWallet purchaseWallet;
private final Analytics analytics;
private WeakReference<NativeExpressAdView> mAdViewReference;
private WeakReference<Button> mUpsellReference;
private PurchaseManager purchaseManager;
@Inject
FreeAdManager(PurchaseWallet purchaseWallet, Analytics analytics) {
// note: Dagger throws exception if there is null in parameters.
// So, no need in additional check
// this.purchaseWallet = Preconditions.checkNotNull(purchaseWallet);
this.purchaseWallet = purchaseWallet;
this.analytics = analytics;
}
public synchronized void onActivityCreated(@NonNull final Activity activity, @Nullable PurchaseManager purchaseManager) {
this.purchaseManager = purchaseManager;
final ViewGroup container = (ViewGroup) activity.findViewById(R.id.adView_container);
final Button upsell = (Button) activity.findViewById(R.id.adView_upsell);
final NativeExpressAdView adView = new NativeExpressAdView(activity);
adView.setAdSize(calculateAdSize());
adView.setAdUnitId(activity.getResources().getString(R.string.adUnitId));
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
adView.setLayoutParams(params);
container.addView(adView);
mAdViewReference = new WeakReference<>(adView);
mUpsellReference = new WeakReference<>(upsell);
if (adView != null) {
if (shouldShowAds(adView)) {
if (showUpsell()) {
analytics.record(Events.Purchases.AdUpsellShown);
adView.setVisibility(View.GONE);
upsell.setVisibility(View.VISIBLE);
} else {
adView.setAdListener(new AdListener() {
@Override
public void onAdFailedToLoad(int errorCode) {
// If we fail to load the ad, just hide it
analytics.record(Events.Purchases.AdUpsellShownOnFailure);
adView.setVisibility(View.GONE);
upsell.setVisibility(View.VISIBLE);
}
@Override
public void onAdLoaded() {
upsell.setVisibility(View.GONE);
}
});
loadAdDelayed(adView);
}
} else {
hideAdAndUpsell();
}
}
if (this.purchaseManager != null) {
this.purchaseManager.addEventListener(this);
}
upsell.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (FreeAdManager.this.purchaseManager != null) {
analytics.record(Events.Purchases.AdUpsellTapped);
FreeAdManager.this.purchaseManager.initiatePurchase(InAppPurchase.SmartReceiptsPlus, PurchaseSource.AdBanner);
}
}
});
}
@NonNull
private AdSize calculateAdSize() {
float density = Resources.getSystem().getDisplayMetrics().density;
int heightPixels = Resources.getSystem().getDisplayMetrics().heightPixels;
int heightDps = (int) (heightPixels / density);
int widthPixels = Resources.getSystem().getDisplayMetrics().widthPixels;
int widthDps = (int) (widthPixels / density);
// Use FULL_WIDTH unless the screen width is greater than the max width
int adWidth = (widthDps < 1200) ? AdSize.FULL_WIDTH : 1200;
if (heightDps < 700) {
return new AdSize(adWidth, 80);
} else if (heightDps < 1000) {
return new AdSize(adWidth, 100);
} else {
return new AdSize(adWidth, 130);
}
}
public synchronized void onResume() {
final NativeExpressAdView adView = mAdViewReference.get();
if (adView != null) {
if (shouldShowAds(adView)) {
adView.resume();
} else {
hideAdAndUpsell();
}
}
}
public synchronized void onPause() {
final NativeExpressAdView adView = mAdViewReference.get();
if (adView != null) {
if (shouldShowAds(adView)) {
adView.pause();
} else {
hideAdAndUpsell();
}
}
}
public synchronized void onDestroy() {
final NativeExpressAdView adView = mAdViewReference.get();
if (adView != null) {
if (shouldShowAds(adView)) {
adView.destroy();
} else {
hideAdAndUpsell();
}
}
if (purchaseManager != null) {
purchaseManager.removeEventListener(this);
}
}
private boolean shouldShowAds(@NonNull NativeExpressAdView adView) {
final boolean hasProSubscription = purchaseManager != null
&& purchaseWallet.hasActivePurchase(InAppPurchase.SmartReceiptsPlus);
final boolean areAdsEnabledLocally = adView.getContext().getSharedPreferences(AD_PREFERENECES, 0).getBoolean(SHOW_AD, true);
return areAdsEnabledLocally && !hasProSubscription;
}
private static AdRequest getAdRequest() {
return new AdRequest.Builder()
.addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
.addTestDevice("BFB48A3556EED9C87CB3AD907780D610")
.addTestDevice("E03AEBCB2894909B8E4EC87C0368C242")
.addTestDevice("B48FF89819FAB2B50FE3E5240FCD9741")
.build();
}
@Override
public synchronized void onPurchaseSuccess(@NonNull InAppPurchase inAppPurchase, @NonNull PurchaseSource purchaseSource) {
Logger.info(this, "Received purchase success in our ad manager for: {}", inAppPurchase);
if (InAppPurchase.SmartReceiptsPlus == inAppPurchase) {
final NativeExpressAdView adView = mAdViewReference.get();
if (adView != null) {
adView.post(new Runnable() {
@Override
public void run() {
if (shouldShowAds(adView)) {
Logger.warn(this, "Showing the original ad following a purchase");
adView.setVisibility(View.VISIBLE);
} else {
Logger.info(this, "Hiding the original ad following a purchase");
hideAdAndUpsell();
}
}
});
}
}
}
@Override
public synchronized void onPurchaseFailed(@NonNull PurchaseSource purchaseSource) {
// Intentional Stub. Handled with parent activity
}
private void hideAdAndUpsell() {
final NativeExpressAdView adView = mAdViewReference.get();
final Button upsell = mUpsellReference.get();
if (adView != null) {
adView.setVisibility(View.GONE);
}
if (upsell != null) {
upsell.setVisibility(View.GONE);
}
}
/**
* The {@link AdView#loadAd(AdRequest)} is really slow and cannot be moved off the main thread (ugh).
* We use this method to slightly defer the ad loading process until the core UI of the app loads, so
* users can see data immediately
*
* @param adView
*/
private void loadAdDelayed(@NonNull final NativeExpressAdView adView) {
adView.postDelayed(new Runnable() {
@Override
public void run() {
try {
adView.loadAd(getAdRequest());
} catch (Exception e) {
Logger.error(this, "Swallowing ad load exception... ", e);
// Swallowing all exception b/c I'm lazy and don't want to handle activity finishing states
}
}
}, 50);
}
private boolean showUpsell() {
final Random random = new Random(SystemClock.uptimeMillis());
return UPSELL_FREQUENCY >= random.nextInt(RANDOM_MAX + 1);
}
}