package com.rjfun.cordova.admob; import java.util.HashMap; import java.util.Iterator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.annotation.SuppressLint; import android.app.Activity; import android.location.Location; import android.os.Bundle; import android.provider.Settings; import android.util.Log; import android.view.View; 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.InterstitialAd; import com.google.android.gms.ads.MobileAds; import com.google.android.gms.ads.doubleclick.PublisherAdRequest; import com.google.android.gms.ads.doubleclick.PublisherAdView; import com.google.android.gms.ads.doubleclick.PublisherInterstitialAd; import com.google.android.gms.ads.mediation.admob.AdMobExtras; import com.google.android.gms.ads.reward.RewardedVideoAd; import com.google.android.gms.ads.reward.RewardedVideoAdListener; import com.google.android.gms.ads.reward.RewardItem; import com.google.ads.mediation.admob.AdMobAdapter; import java.lang.reflect.Method; import java.lang.NoSuchMethodException; import java.util.ArrayList; import com.rjfun.cordova.ad.GenericAdPlugin; public class AdMobPlugin extends GenericAdPlugin { private static final String LOGTAG = "AdMobPlugin"; // options private static final String OPT_ADCOLONY = "AdColony"; private static final String OPT_FLURRY = "Flurry"; private static final String OPT_MMEDIA = "mMedia"; private static final String OPT_INMOBI = "InMobi"; private static final String OPT_FACEBOOK = "Facebook"; private static final String OPT_MOBFOX = "MobFox"; private static final String TEST_BANNER_ID = "ca-app-pub-3940256099942544/6300978111"; private static final String TEST_INTERSTITIAL_ID = "ca-app-pub-3940256099942544/1033173712"; private static final String TEST_REWARDVIDEO_ID = "ca-app-pub-3940256099942544/5224354917"; private AdSize adSize = AdSize.SMART_BANNER; public static final String OPT_AD_EXTRAS = "adExtras"; private JSONObject adExtras = null; public static final String OPT_LOCATION = "location"; private Location mLocation = null; public static final String OPT_GENDER = "gender"; public static final String OPT_FORCHILD = "forChild"; public static final String OPT_FORFAMILY = "forFamily"; public static final String OPT_CONTENTURL = "contentUrl"; public static final String OPT_CUSTOMTARGETING = "customTargeting"; public static final String OPT_EXCLUDE = "exclude"; protected String mGender = null; protected String mForChild = null; protected String mForFamily = null; protected String mContentURL = null; protected JSONObject mCustomTargeting = null; protected JSONArray mExclude = null; private boolean mIsRewardedVideoLoading = false; private final Object mLock = new Object(); private HashMap<String, AdMobMediation> mediations = new HashMap<String, AdMobMediation>(); @Override protected void pluginInitialize() { super.pluginInitialize(); // TODO: any init code } @Override protected String __getProductShortName() { return "AdMob"; } @Override protected String __getTestBannerId() { return TEST_BANNER_ID; } @Override protected String __getTestInterstitialId() { return TEST_INTERSTITIAL_ID; } @Override protected String __getTestRewardVideoId() { return TEST_REWARDVIDEO_ID; } @Override public void setOptions(JSONObject options) { super.setOptions(options); if(options.has(OPT_AD_SIZE)) adSize = adSizeFromString(options.optString(OPT_AD_SIZE)); if(adSize == null) { adSize = new AdSize(adWidth, adHeight); } if(options.has(OPT_AD_EXTRAS)) adExtras = options.optJSONObject(OPT_AD_EXTRAS); if(options.has(OPT_LOCATION)) { JSONArray location = options.optJSONArray(OPT_LOCATION); if(location != null) { mLocation = new Location("dummyprovider"); mLocation.setLatitude( location.optDouble(0, 0.0) ); mLocation.setLongitude( location.optDouble(1, 0) ); } } if(options.has(OPT_GENDER)) { mGender = options.optString(OPT_GENDER); } if(options.has(OPT_FORCHILD)) { mForChild = options.optString(OPT_FORCHILD); } if(options.has(OPT_FORFAMILY)) { mForFamily = options.optString(OPT_FORFAMILY); } if(options.has(OPT_CONTENTURL)) { mContentURL = options.optString(OPT_CONTENTURL); } if(options.has(OPT_CUSTOMTARGETING)) { mCustomTargeting = options.optJSONObject(OPT_CUSTOMTARGETING); } if(options.has(OPT_EXCLUDE)) { mExclude = options.optJSONArray(OPT_EXCLUDE); } } @Override protected View __createAdView(String adId) { // safety check to avoid exception when adId is null or empty if(adId==null || adId.length()==0) adId = TEST_BANNER_ID; // Tip: The format for the DFP ad unit ID is: /networkCode/adUnitName // example: "/6253334/dfp_example_ad" if(adId.charAt(0) == '/') { PublisherAdView ad = new PublisherAdView(getActivity()); ad.setAdUnitId(adId); ad.setAdSizes(adSize); ad.setAdListener(new BannerListener()); return ad; } else { AdView ad = new AdView(getActivity()); ad.setAdUnitId(adId); ad.setAdSize(adSize); ad.setAdListener(new BannerListener()); return ad; } } @Override protected void __loadAdView(View view) { if(view instanceof PublisherAdView) { PublisherAdView ad = (PublisherAdView) view; ad.loadAd(buildPublisherAdRequest()); } else { AdView ad = (AdView) view; ad.loadAd(buildAdRequest()); } } protected AdSize getAdViewSize(View view) { if(view instanceof PublisherAdView) { PublisherAdView dfpView = (PublisherAdView) view; return dfpView.getAdSize(); } else if(view instanceof AdView) { AdView admobView = (AdView) view; return admobView.getAdSize(); } else { return new AdSize(0,0); } } @Override protected int __getAdViewWidth(View view) { AdSize sz = getAdViewSize(view); return sz.getWidthInPixels(getActivity()); } @Override protected int __getAdViewHeight(View view) { AdSize sz = getAdViewSize(view); return sz.getHeightInPixels(getActivity()); } @Override protected void __pauseAdView(View view) { if(view == null) return; if(view instanceof PublisherAdView) { PublisherAdView dfpView = (PublisherAdView)view; dfpView.pause(); } else { AdView admobView = (AdView)view; admobView.pause(); } } @Override protected void __resumeAdView(View view) { if(view == null) return; if(view instanceof PublisherAdView) { PublisherAdView dfpView = (PublisherAdView)view; dfpView.resume(); } else { AdView admobView = (AdView)view; admobView.resume(); } } @Override protected void __destroyAdView(View view) { if(view == null) return; if(view instanceof PublisherAdView) { PublisherAdView dfpView = (PublisherAdView)view; dfpView.setAdListener(null); dfpView.destroy(); } else { AdView admobView = (AdView)view; admobView.setAdListener(null); admobView.destroy(); } } @Override protected Object __createInterstitial(String adId) { interstitialReady = false; // safety check to avoid exceptoin in case adId is null or empty if(adId==null || adId.length()==0) adId = TEST_INTERSTITIAL_ID; if(adId.charAt(0) == '/') { PublisherInterstitialAd ad = new PublisherInterstitialAd(getActivity()); ad.setAdUnitId(adId); ad.setAdListener(new InterstitialListener()); return ad; } else { InterstitialAd ad = new InterstitialAd(getActivity()); ad.setAdUnitId(adId); ad.setAdListener(new InterstitialListener()); return ad; } } @Override protected void __loadInterstitial(Object interstitial) { if(interstitial == null) return; if(interstitial instanceof PublisherInterstitialAd) { PublisherInterstitialAd ad = (PublisherInterstitialAd) interstitial; ad.loadAd(buildPublisherAdRequest()); } else if(interstitial instanceof InterstitialAd) { InterstitialAd ad = (InterstitialAd) interstitial; ad.loadAd( buildAdRequest() ); } } @Override protected void __showInterstitial(Object interstitial) { if(interstitial == null) return; if(interstitial instanceof PublisherInterstitialAd) { PublisherInterstitialAd ad = (PublisherInterstitialAd) interstitial; if(ad.isLoaded()) { ad.show(); } }else if(interstitial instanceof InterstitialAd){ InterstitialAd ad = (InterstitialAd) interstitial; if(ad.isLoaded()) { ad.show(); } } } @Override protected void __destroyInterstitial(Object interstitial) { if(interstitial == null) return; if(interstitial instanceof InterstitialAd) { InterstitialAd ad = (InterstitialAd) interstitial; ad.setAdListener(null); } } @Override protected Object __prepareRewardVideoAd(String adId) { // safety check to avoid exceptoin in case adId is null or empty if(adId==null || adId.length()==0) adId = TEST_REWARDVIDEO_ID; RewardedVideoAd ad = MobileAds.getRewardedVideoAdInstance(getActivity()); ad.setRewardedVideoAdListener(new RewardVideoListener()); synchronized (mLock) { if (!mIsRewardedVideoLoading) { mIsRewardedVideoLoading = true; Bundle extras = new Bundle(); extras.putBoolean("_noRefresh", true); AdRequest adRequest = new AdRequest.Builder() .addNetworkExtrasBundle(AdMobAdapter.class, extras) .build(); ad.loadAd(adId, adRequest); } } return ad; } @Override protected void __showRewardVideoAd(Object rewardvideo) { if(rewardvideo == null) return; if(rewardvideo instanceof RewardedVideoAd) { RewardedVideoAd ad = (RewardedVideoAd) rewardvideo; if(ad.isLoaded()){ ad.show(); } } } @SuppressLint("DefaultLocale") private AdRequest buildAdRequest() { final Activity activity = getActivity(); AdRequest.Builder builder = new AdRequest.Builder(); if (isTesting) { // This will request test ads on the emulator and deviceby passing this hashed device ID. String ANDROID_ID = Settings.Secure.getString(activity.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); String deviceId = md5(ANDROID_ID).toUpperCase(); builder = builder.addTestDevice(deviceId).addTestDevice(AdRequest.DEVICE_ID_EMULATOR); } if(adExtras != null) { Bundle bundle = new Bundle(); bundle.putInt("cordova", 1); Iterator<String> it = adExtras.keys(); while (it.hasNext()) { String key = it.next(); try { bundle.putString(key, adExtras.get(key).toString()); } catch (JSONException exception) { Log.w(LOGTAG, String.format("Caught JSON Exception: %s", exception.getMessage())); } } builder = builder.addNetworkExtras( new AdMobExtras(bundle) ); } Iterator<String> it = mediations.keySet().iterator(); while(it.hasNext()) { String key = it.next(); AdMobMediation m = mediations.get(key); if(m != null) { builder = m.joinAdRequest(builder); } } if(mLocation != null) builder.setLocation(mLocation); if(mForFamily != null) { Bundle extras = new Bundle(); extras.putBoolean("is_designed_for_families", true); builder.addNetworkExtrasBundle(AdMobAdapter.class, extras); } if(mForChild != null) { builder.tagForChildDirectedTreatment(true); } if(mContentURL != null) { builder.setContentUrl(mContentURL); } return builder.build(); } @SuppressLint("DefaultLocale") private PublisherAdRequest buildPublisherAdRequest() { final Activity activity = getActivity(); PublisherAdRequest.Builder builder = new PublisherAdRequest.Builder(); if (isTesting) { // This will request test ads on the emulator and deviceby passing this hashed device ID. String ANDROID_ID = Settings.Secure.getString(activity.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); String deviceId = md5(ANDROID_ID).toUpperCase(); builder = builder.addTestDevice(deviceId).addTestDevice(AdRequest.DEVICE_ID_EMULATOR); } if(adExtras != null) { Bundle bundle = new Bundle(); bundle.putInt("cordova", 1); Iterator<String> it = adExtras.keys(); while (it.hasNext()) { String key = it.next(); try { bundle.putString(key, adExtras.get(key).toString()); } catch (JSONException exception) { Log.w(LOGTAG, String.format("Caught JSON Exception: %s", exception.getMessage())); } } builder = builder.addNetworkExtras(new AdMobExtras(bundle)); } if(mLocation != null) builder.setLocation(mLocation); if(mForFamily != null) { Bundle extras = new Bundle(); extras.putBoolean("is_designed_for_families", ("yes".compareToIgnoreCase(mForFamily) == 0)); builder.addNetworkExtrasBundle(AdMobAdapter.class, extras); } if(mForChild != null) { builder.tagForChildDirectedTreatment("yes".compareToIgnoreCase(mForChild) == 0); } if(mContentURL != null) { builder.setContentUrl(mContentURL); } // DFP extra targeting options if(mCustomTargeting != null) { Iterator<String> iter = mCustomTargeting.keys(); while(iter.hasNext()){ String key = iter.next(); String str = mCustomTargeting.optString(key); if(str!=null && str.length()>0) { builder.addCustomTargeting(key, str); } else { JSONArray strs = mCustomTargeting.optJSONArray(key); if(strs!=null && strs.length()>0) { ArrayList<String> strlist = new ArrayList<String>(); for(int i=0; i<strs.length(); i++) strlist.add(strs.optString(i)); builder.addCustomTargeting(key, strlist); } } } } if(mExclude != null) { int n = mExclude.length(); if(n > 0) { try { // new method after SDK v7.0 Method method = null; method = builder.getClass().getMethod("addCategoryExclusion", String.class); if (method != null) { try { for (int i = 0; i < n; i++) { method.invoke(builder, mExclude.optString(i, "")); } } catch (Exception e) { } } } catch (NoSuchMethodException e) { // old method before SDK v7.0 Bundle bundle = new Bundle(); String str = ""; for(int i=0; i<n; i++) { if(i > 0) str += ","; str += mExclude.optString(i, ""); } bundle.putString("excl_cat", str); builder.addNetworkExtras(new AdMobExtras(bundle)); } } } return builder.build(); } @Override public void onPause(boolean multitasking) { Iterator<String> it = mediations.keySet().iterator(); while(it.hasNext()) { String key = it.next(); AdMobMediation m = mediations.get(key); if(m != null) m.onPause(); } super.onPause(multitasking); } @Override public void onResume(boolean multitasking) { super.onResume(multitasking); Iterator<String> it = mediations.keySet().iterator(); while(it.hasNext()) { String key = it.next(); AdMobMediation m = mediations.get(key); if(m != null) m.onResume(); } } @Override public void onDestroy() { Iterator<String> it = mediations.keySet().iterator(); while(it.hasNext()) { String key = it.next(); AdMobMediation m = mediations.get(key); if(m != null) m.onDestroy(); } super.onDestroy(); } /** * Gets an AdSize object from the string size passed in from JavaScript. * Returns null if an improper string is provided. * * @param size The string size representing an ad format constant. * @return An AdSize object used to create a banner. */ public static AdSize adSizeFromString(String size) { if ("BANNER".equals(size)) { return AdSize.BANNER; } else if ("SMART_BANNER".equals(size)) { return AdSize.SMART_BANNER; } else if ("MEDIUM_RECTANGLE".equals(size)) { return AdSize.MEDIUM_RECTANGLE; } else if ("FULL_BANNER".equals(size)) { return AdSize.FULL_BANNER; } else if ("LEADERBOARD".equals(size)) { return AdSize.LEADERBOARD; } else if ("SKYSCRAPER".equals(size)) { return AdSize.WIDE_SKYSCRAPER; } else if ("LARGE_BANNER".equals(size)) { return AdSize.LARGE_BANNER; } else { return null; } } /** * document.addEventListener('onAdLoaded', function(data)); * document.addEventListener('onAdFailLoad', function(data)); * document.addEventListener('onAdPresent', function(data)); * document.addEventListener('onAdDismiss', function(data)); * document.addEventListener('onAdLeaveApp', function(data)); */ private class BannerListener extends AdListener { @SuppressLint("DefaultLocale") @Override public void onAdFailedToLoad(int errorCode) { fireAdErrorEvent(EVENT_AD_FAILLOAD, errorCode, getErrorReason(errorCode), ADTYPE_BANNER); } @Override public void onAdLeftApplication() { fireAdEvent(EVENT_AD_LEAVEAPP, ADTYPE_BANNER); } @Override public void onAdLoaded() { if(autoShowBanner && (!bannerVisible)) { showBanner(adPosition, posX, posY); } fireAdEvent(EVENT_AD_LOADED, ADTYPE_BANNER); } @Override public void onAdOpened() { fireAdEvent(EVENT_AD_PRESENT, ADTYPE_BANNER); } @Override public void onAdClosed() { fireAdEvent(EVENT_AD_DISMISS, ADTYPE_BANNER); } } /** * document.addEventListener('onAdLoaded', function(data)); * document.addEventListener('onAdFailLoad', function(data)); * document.addEventListener('onAdPresent', function(data)); * document.addEventListener('onAdDismiss', function(data)); * document.addEventListener('onAdLeaveApp', function(data)); */ private class InterstitialListener extends AdListener { @SuppressLint("DefaultLocale") @Override public void onAdFailedToLoad(int errorCode) { fireAdErrorEvent(EVENT_AD_FAILLOAD, errorCode, getErrorReason(errorCode), ADTYPE_INTERSTITIAL); } @Override public void onAdLeftApplication() { fireAdEvent(EVENT_AD_LEAVEAPP, ADTYPE_INTERSTITIAL); } @Override public void onAdLoaded() { interstitialReady = true; if(autoShowInterstitial) { showInterstitial(); } fireAdEvent(EVENT_AD_LOADED, ADTYPE_INTERSTITIAL); } @Override public void onAdOpened() { fireAdEvent(EVENT_AD_PRESENT, ADTYPE_INTERSTITIAL); } @Override public void onAdClosed() { fireAdEvent(EVENT_AD_DISMISS, ADTYPE_INTERSTITIAL); removeInterstitial(); // if focus on webview of banner, press back button will quit // force focus on main view, so that 'backbutton' override will work View mainView = getView(); if (mainView != null) { mainView.requestFocus(); } } } /** * document.addEventListener('onAdLoaded', function(data)); * document.addEventListener('onAdFailLoad', function(data)); * document.addEventListener('onAdPresent', function(data)); * document.addEventListener('onAdDismiss', function(data)); * document.addEventListener('onAdLeaveApp', function(data)); */ private class RewardVideoListener implements RewardedVideoAdListener { @SuppressLint("DefaultLocale") @Override public void onRewardedVideoAdFailedToLoad(int errorCode) { synchronized (mLock) { mIsRewardedVideoLoading = false; } rewardVideoAd = null; //<-- Added line before the fireAdEvent fireAdErrorEvent(EVENT_AD_FAILLOAD, errorCode, getErrorReason(errorCode), ADTYPE_REWARDVIDEO); } @Override public void onRewardedVideoAdLeftApplication() { fireAdEvent(EVENT_AD_LEAVEAPP, ADTYPE_REWARDVIDEO); } @Override public void onRewardedVideoAdLoaded() { synchronized (mLock) { mIsRewardedVideoLoading = false; } fireAdEvent(EVENT_AD_LOADED, ADTYPE_REWARDVIDEO); if(autoShowRewardVideo) { showRewardVideoAd(); } } @Override public void onRewardedVideoAdOpened() { fireAdEvent(EVENT_AD_WILLPRESENT, ADTYPE_REWARDVIDEO); } @Override public void onRewardedVideoStarted() { fireAdEvent(EVENT_AD_WILLPRESENT, ADTYPE_REWARDVIDEO); } //@Override public void onRewardedVideoCompleted() { fireAdEvent(EVENT_AD_WILLDISMISS, ADTYPE_REWARDVIDEO); } @Override public void onRewardedVideoAdClosed() { rewardVideoAd = null; //<-- Added line before the fireAdEvent fireAdEvent(EVENT_AD_DISMISS, ADTYPE_REWARDVIDEO); // if focus on webview of banner, press back button will quit // force focus on main view, so that 'backbutton' override will work View mainView = getView(); if (mainView != null) { mainView.requestFocus(); } } @Override public void onRewarded(RewardItem reward) { String obj = __getProductShortName(); String json = String.format("{'adNetwork':'%s','adType':'%s','adEvent':'%s','rewardType':'%s','rewardAmount':%d}", obj, ADTYPE_REWARDVIDEO, EVENT_AD_PRESENT, reward.getType(), reward.getAmount()); fireEvent(obj, EVENT_AD_PRESENT, json); } } /** Gets a string error reason from an error code. */ public String getErrorReason(int errorCode) { String errorReason = ""; switch(errorCode) { case AdRequest.ERROR_CODE_INTERNAL_ERROR: errorReason = "Internal error"; break; case AdRequest.ERROR_CODE_INVALID_REQUEST: errorReason = "Invalid request"; break; case AdRequest.ERROR_CODE_NETWORK_ERROR: errorReason = "Network Error"; break; case AdRequest.ERROR_CODE_NO_FILL: errorReason = "No fill"; break; } return errorReason; } }