/*
* Copyright (c) 2010, MoPub Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'MoPub Inc.' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.mopub.mobileads;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.webkit.WebViewDatabase;
import android.widget.FrameLayout;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Map;
public class MoPubView extends FrameLayout {
public interface BannerAdListener {
public void onBannerLoaded(MoPubView banner);
public void onBannerFailed(MoPubView banner, MoPubErrorCode errorCode);
public void onBannerClicked(MoPubView banner);
public void onBannerExpanded(MoPubView banner);
public void onBannerCollapsed(MoPubView banner);
}
public enum LocationAwareness {
LOCATION_AWARENESS_NORMAL, LOCATION_AWARENESS_TRUNCATED, LOCATION_AWARENESS_DISABLED
}
public static final String HOST = "ads.mopub.com";
public static final String HOST_FOR_TESTING = "testing.ads.mopub.com";
public static final String AD_HANDLER = "/m/ad";
public static final int DEFAULT_LOCATION_PRECISION = 6;
protected AdView mAdView;
protected BaseAdapter mAdapter;
private Context mContext;
private BroadcastReceiver mScreenStateReceiver;
private boolean mIsInForeground;
private LocationAwareness mLocationAwareness;
private int mLocationPrecision;
private boolean mPreviousAutorefreshSetting = false;
private BannerAdListener mBannerAdListener;
private OnAdWillLoadListener mOnAdWillLoadListener;
private OnAdLoadedListener mOnAdLoadedListener;
private OnAdFailedListener mOnAdFailedListener;
private OnAdPresentedOverlayListener mOnAdPresentedOverlayListener;
private OnAdClosedListener mOnAdClosedListener;
private OnAdClickedListener mOnAdClickedListener;
public MoPubView(Context context) {
this(context, null);
}
public MoPubView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
mIsInForeground = (getVisibility() == VISIBLE);
mLocationAwareness = LocationAwareness.LOCATION_AWARENESS_NORMAL;
mLocationPrecision = DEFAULT_LOCATION_PRECISION;
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
// There is a rare bug in Froyo/2.2 where creation of a WebView causes a
// NullPointerException. (http://code.google.com/p/android/issues/detail?id=10789)
// It happens when the WebView can't access the local file store to make a cache file.
// Here, we'll work around it by trying to create a file store and then just go inert
// if it's not accessible.
if (WebViewDatabase.getInstance(context) == null) {
Log.e("MoPub", "Disabling MoPub. Local cache file is inaccessible so MoPub will " +
"fail if we try to create a WebView. Details of this Android bug found at:" +
"http://code.google.com/p/android/issues/detail?id=10789");
return;
}
initVersionDependentAdView(context);
registerScreenStateBroadcastReceiver();
}
private void initVersionDependentAdView(Context context) {
int sdkVersion = (new Integer(Build.VERSION.SDK)).intValue();
if (sdkVersion < 7) {
mAdView = new AdView(context, this);
} else {
// On Android 2.1 (Eclair) and up, try to load our HTML5-enabled AdView class.
Class<?> HTML5AdViewClass = null;
try {
HTML5AdViewClass = (Class<?>) Class.forName("com.mopub.mobileads.HTML5AdView");
} catch (ClassNotFoundException e) {
mAdView = new AdView(context, this);
return;
}
Class<?>[] parameterTypes = new Class[2];
parameterTypes[0] = Context.class;
parameterTypes[1] = MoPubView.class;
Object[] args = new Object[2];
args[0] = context;
args[1] = this;
try {
Constructor<?> constructor = HTML5AdViewClass.getConstructor(parameterTypes);
mAdView = (AdView) constructor.newInstance(args);
} catch (SecurityException e) {
Log.e("MoPub", "Could not load HTML5AdView.");
} catch (NoSuchMethodException e) {
Log.e("MoPub", "Could not load HTML5AdView.");
} catch (IllegalArgumentException e) {
Log.e("MoPub", "Could not load HTML5AdView.");
} catch (InstantiationException e) {
Log.e("MoPub", "Could not load HTML5AdView.");
} catch (IllegalAccessException e) {
Log.e("MoPub", "Could not load HTML5AdView.");
} catch (InvocationTargetException e) {
Log.e("MoPub", "Could not load HTML5AdView.");
}
if (mAdView == null) mAdView = new AdView(context, this);
}
}
private void registerScreenStateBroadcastReceiver() {
if (mAdView == null) return;
mScreenStateReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
if (mIsInForeground) {
Log.d("MoPub", "Screen sleep with ad in foreground, disable refresh");
if (mAdView != null) {
mPreviousAutorefreshSetting = mAdView.getAutorefreshEnabled();
mAdView.setAutorefreshEnabled(false);
}
} else {
Log.d("MoPub", "Screen sleep but ad in background; " +
"refresh should already be disabled");
}
} else if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
if (mIsInForeground) {
Log.d("MoPub", "Screen wake / ad in foreground, reset refresh");
if (mAdView != null) {
mAdView.setAutorefreshEnabled(mPreviousAutorefreshSetting);
}
} else {
Log.d("MoPub", "Screen wake but ad in background; don't enable refresh");
}
}
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
mContext.registerReceiver(mScreenStateReceiver, filter);
}
private void unregisterScreenStateBroadcastReceiver() {
try {
mContext.unregisterReceiver(mScreenStateReceiver);
} catch (Exception IllegalArgumentException) {
Log.d("MoPub", "Failed to unregister screen state broadcast receiver (never registered).");
}
}
public void loadAd() {
if (mAdView != null) mAdView.loadAd();
}
/*
* Tears down the ad view: no ads will be shown once this method executes. The parent
* Activity's onDestroy implementation must include a call to this method.
*/
public void destroy() {
unregisterScreenStateBroadcastReceiver();
removeAllViews();
if (mAdView != null) {
mAdView.cleanup();
mAdView = null;
}
if (mAdapter != null) {
mAdapter.invalidate();
mAdapter = null;
}
}
protected void loadFailUrl(MoPubErrorCode errorCode) {
if (mAdView != null) mAdView.loadFailUrl(errorCode);
}
protected void loadNativeSDK(Map<String, String> paramsMap) {
if (mAdapter != null) mAdapter.invalidate();
String type = paramsMap.get("X-Adtype");
mAdapter = BaseAdapter.getAdapterForType(type);
if (mAdapter != null) {
Log.i("MoPub", "Loading native adapter for type: " + type);
String jsonParams = paramsMap.get("X-Nativeparams");
mAdapter.init(this, jsonParams);
mAdapter.loadAd();
} else {
Log.i("MoPub", "Couldn't load native adapter. Trying next ad...");
loadFailUrl(MoPubErrorCode.ADAPTER_NOT_FOUND);
}
}
protected void loadCustomEvent(Map<String, String> paramsMap) {
if (mAdapter != null) mAdapter.invalidate();
mAdapter = BaseAdapter.getAdapterForType("custom_event");
if (mAdapter != null) {
Log.i("MoPub", "Loading custom event adapter.");
// Get the className and classData from the passed in paramsMap.
String className = paramsMap.get("X-Custom-Event-Class-Name");
String classData = paramsMap.get("X-Custom-Event-Class-Data");
((CustomEventBannerAdapter) mAdapter).init(this, className, classData);
mAdapter.loadAd();
} else {
Log.i("MoPub", "Couldn't load custom event adapter. Trying next ad...");
loadFailUrl(MoPubErrorCode.ADAPTER_NOT_FOUND);
}
}
protected void registerClick() {
if (mAdView != null) {
mAdView.registerClick();
// Let any listeners know that an ad was clicked
adClicked();
}
}
protected void loadHtmlString(String html) {
if (mAdView != null) mAdView.loadResponseString(html);
}
protected void trackNativeImpression() {
Log.d("MoPub", "Tracking impression for native adapter.");
if (mAdView != null) mAdView.trackImpression();
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
if (mAdView == null) return;
if (visibility == VISIBLE) {
Log.d("MoPub", "Ad Unit ("+mAdView.getAdUnitId()+") going visible: enabling refresh");
mIsInForeground = true;
mAdView.setAutorefreshEnabled(true);
}
else {
Log.d("MoPub", "Ad Unit ("+mAdView.getAdUnitId()+") going invisible: disabling refresh");
mIsInForeground = false;
mAdView.setAutorefreshEnabled(false);
}
}
protected void adLoaded() {
Log.d("MoPub", "adLoaded");
if (mBannerAdListener != null) {
mBannerAdListener.onBannerLoaded(this);
} else if (mOnAdLoadedListener != null) {
mOnAdLoadedListener.OnAdLoaded(this);
}
}
protected void adFailed(MoPubErrorCode errorCode) {
if (mBannerAdListener != null) {
mBannerAdListener.onBannerFailed(this, errorCode);
} else if (mOnAdFailedListener != null) {
mOnAdFailedListener.OnAdFailed(this);
}
}
protected void adPresentedOverlay() {
if (mBannerAdListener != null) {
mBannerAdListener.onBannerExpanded(this);
} else if (mOnAdPresentedOverlayListener != null) {
mOnAdPresentedOverlayListener.OnAdPresentedOverlay(this);
}
}
protected void adClosed() {
if (mBannerAdListener != null) {
mBannerAdListener.onBannerCollapsed(this);
} else if (mOnAdClosedListener != null) {
mOnAdClosedListener.OnAdClosed(this);
}
}
protected void adClicked() {
if (mBannerAdListener != null) {
mBannerAdListener.onBannerClicked(this);
} else if (mOnAdClickedListener != null) {
mOnAdClickedListener.OnAdClicked(this);
}
}
protected void nativeAdLoaded() {
if (mAdView != null) mAdView.scheduleRefreshTimerIfEnabled();
adLoaded();
}
protected void adAppeared() {
if (mAdView != null) mAdView.adAppeared();
}
////////////////////////////////////////////////////////////////////////////////////////////////
public void setAdUnitId(String adUnitId) {
if (mAdView != null) mAdView.setAdUnitId(adUnitId);
}
public void setKeywords(String keywords) {
if (mAdView != null) mAdView.setKeywords(keywords);
}
public String getKeywords() {
return (mAdView != null) ? mAdView.getKeywords() : null;
}
public void setLocation(Location location) {
if (mAdView != null) mAdView.setLocation(location);
}
public Location getLocation() {
return (mAdView != null) ? mAdView.getLocation() : null;
}
public void setTimeout(int milliseconds) {
if (mAdView != null) mAdView.setTimeout(milliseconds);
}
public int getAdWidth() {
return (mAdView != null) ? mAdView.getAdWidth() : 0;
}
public int getAdHeight() {
return (mAdView != null) ? mAdView.getAdHeight() : 0;
}
public String getResponseString() {
return (mAdView != null) ? mAdView.getResponseString() : null;
}
public void setClickthroughUrl(String url) {
if (mAdView != null) mAdView.setClickthroughUrl(url);
}
public String getClickthroughUrl() {
return (mAdView != null) ? mAdView.getClickthroughUrl() : null;
}
public Activity getActivity() {
return (Activity) mContext;
}
public void setBannerAdListener(BannerAdListener listener) {
mBannerAdListener = listener;
}
public BannerAdListener getBannerAdListener() {
return mBannerAdListener;
}
public void setLocationAwareness(LocationAwareness awareness) {
mLocationAwareness = awareness;
}
public LocationAwareness getLocationAwareness() {
return mLocationAwareness;
}
public void setLocationPrecision(int precision) {
mLocationPrecision = (precision >= 0) ? precision : 0;
}
public int getLocationPrecision() {
return mLocationPrecision;
}
public void setLocalExtras(Map<String, Object> localExtras) {
if (mAdView != null) mAdView.setLocalExtras(localExtras);
}
public Map<String, Object> getLocalExtras() {
if (mAdView != null) return mAdView.getLocalExtras();
return Collections.emptyMap();
}
public void setAutorefreshEnabled(boolean enabled) {
if (mAdView != null) mAdView.setAutorefreshEnabled(enabled);
}
public boolean getAutorefreshEnabled() {
if (mAdView != null) return mAdView.getAutorefreshEnabled();
else {
Log.d("MoPub", "Can't get autorefresh status for destroyed MoPubView. " +
"Returning false.");
return false;
}
}
public void setAdContentView(View view) {
if (mAdView != null) mAdView.setAdContentView(view);
}
public void setTesting(boolean testing) {
if (mAdView != null) mAdView.setTesting(testing);
}
public boolean getTesting() {
if (mAdView != null) return mAdView.getTesting();
else {
Log.d("MoPub", "Can't get testing status for destroyed MoPubView. " +
"Returning false.");
return false;
}
}
public void forceRefresh() {
if (mAdapter != null) {
mAdapter.invalidate();
mAdapter = null;
}
if (mAdView != null) mAdView.forceRefresh();
}
@Deprecated
public interface OnAdWillLoadListener {
public void OnAdWillLoad(MoPubView m, String url);
}
@Deprecated
public interface OnAdLoadedListener {
public void OnAdLoaded(MoPubView m);
}
@Deprecated
public interface OnAdFailedListener {
public void OnAdFailed(MoPubView m);
}
@Deprecated
public interface OnAdClosedListener {
public void OnAdClosed(MoPubView m);
}
@Deprecated
public interface OnAdClickedListener {
public void OnAdClicked(MoPubView m);
}
@Deprecated
public interface OnAdPresentedOverlayListener {
public void OnAdPresentedOverlay(MoPubView m);
}
@Deprecated
public void setOnAdWillLoadListener(OnAdWillLoadListener listener) {
mOnAdWillLoadListener = listener;
}
@Deprecated
public void setOnAdLoadedListener(OnAdLoadedListener listener) {
mOnAdLoadedListener = listener;
}
@Deprecated
public void setOnAdFailedListener(OnAdFailedListener listener) {
mOnAdFailedListener = listener;
}
@Deprecated
public void setOnAdPresentedOverlayListener(OnAdPresentedOverlayListener listener) {
mOnAdPresentedOverlayListener = listener;
}
@Deprecated
public void setOnAdClosedListener(OnAdClosedListener listener) {
mOnAdClosedListener = listener;
}
@Deprecated
public void setOnAdClickedListener(OnAdClickedListener listener) {
mOnAdClickedListener = listener;
}
@Deprecated
protected void adWillLoad(String url) {
Log.d("MoPub", "adWillLoad: " + url);
if (mOnAdWillLoadListener != null) mOnAdWillLoadListener.OnAdWillLoad(this, url);
}
@Deprecated
public void customEventDidLoadAd() {
if (mAdView != null) mAdView.customEventDidLoadAd();
}
@Deprecated
public void customEventDidFailToLoadAd() {
if (mAdView != null) mAdView.customEventDidFailToLoadAd();
}
@Deprecated
public void customEventActionWillBegin() {
if (mAdView != null) mAdView.customEventActionWillBegin();
}
}