package com.mopub.nativeads;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.mopub.common.VisibleForTesting;
import com.mopub.common.event.MoPubEvents;
import com.mopub.common.logging.MoPubLog;
import com.mopub.nativeads.MoPubNative.MoPubNativeEventListener;
import com.mopub.network.Networking;
import com.mopub.network.TrackingRequest;
import com.mopub.volley.VolleyError;
import com.mopub.volley.toolbox.ImageLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static android.view.View.OnClickListener;
import static com.mopub.nativeads.BaseForwardingNativeAd.NativeEventListener;
import static com.mopub.nativeads.NativeResponse.Parameter.CALL_TO_ACTION;
import static com.mopub.nativeads.NativeResponse.Parameter.CLICK_DESTINATION;
import static com.mopub.nativeads.NativeResponse.Parameter.CLICK_TRACKER;
import static com.mopub.nativeads.NativeResponse.Parameter.ICON_IMAGE;
import static com.mopub.nativeads.NativeResponse.Parameter.IMPRESSION_TRACKER;
import static com.mopub.nativeads.NativeResponse.Parameter.MAIN_IMAGE;
import static com.mopub.nativeads.NativeResponse.Parameter.STAR_RATING;
import static com.mopub.nativeads.NativeResponse.Parameter.TEXT;
import static com.mopub.nativeads.NativeResponse.Parameter.TITLE;
public class NativeResponse {
enum Parameter {
IMPRESSION_TRACKER("imptracker", true),
CLICK_TRACKER("clktracker", true),
TITLE("title", false),
TEXT("text", false),
MAIN_IMAGE("mainimage", false),
ICON_IMAGE("iconimage", false),
CLICK_DESTINATION("clk", false),
FALLBACK("fallback", false),
CALL_TO_ACTION("ctatext", false),
STAR_RATING("starrating", false);
@NonNull final String name;
final boolean required;
Parameter(@NonNull final String name, boolean required) {
this.name = name;
this.required = required;
}
@Nullable
static Parameter from(@NonNull final String name) {
for (final Parameter parameter : values()) {
if (parameter.name.equals(name)) {
return parameter;
}
}
return null;
}
@NonNull
@VisibleForTesting
static final Set<String> requiredKeys = new HashSet<String>();
static {
for (final Parameter parameter : values()) {
if (parameter.required) {
requiredKeys.add(parameter.name);
}
}
}
}
@NonNull private final Context mContext;
@NonNull private final ImageLoader mImageLoader;
@NonNull private MoPubNativeEventListener mMoPubNativeEventListener;
@NonNull private final NativeAdInterface mNativeAd;
// Impression and click trackers for the MoPub adserver
@NonNull private final Set<String> mMoPubImpressionTrackers;
@NonNull private final String mMoPubClickTracker;
@NonNull private final String mAdUnitId;
private boolean mRecordedImpression;
private boolean mIsClicked;
private boolean mIsDestroyed;
public NativeResponse(@NonNull final Context context,
@NonNull final String impressionUrl,
@NonNull final String clickUrl,
@NonNull final String adUnitId,
@NonNull final NativeAdInterface nativeAd,
@NonNull final MoPubNativeEventListener moPubNativeEventListener) {
mContext = context.getApplicationContext();
mAdUnitId = adUnitId;
mMoPubNativeEventListener = moPubNativeEventListener;
mNativeAd = nativeAd;
mNativeAd.setNativeEventListener(new NativeEventListener() {
@Override
public void onAdImpressed() {
recordImpression(null);
}
@Override
public void onAdClicked() {
handleClick(null);
}
});
mMoPubImpressionTrackers = new HashSet<String>();
mMoPubImpressionTrackers.add(impressionUrl);
mMoPubClickTracker = clickUrl;
mImageLoader = Networking.getImageLoader(context);
}
@Override
public String toString() {
final StringBuilder stringBuilder = new StringBuilder("\n");
stringBuilder.append(TITLE.name).append(":").append(getTitle()).append("\n");
stringBuilder.append(TEXT.name).append(":").append(getText()).append("\n");
stringBuilder.append(ICON_IMAGE.name).append(":").append(getIconImageUrl()).append("\n");
stringBuilder.append(MAIN_IMAGE.name).append(":").append(getMainImageUrl()).append("\n");
stringBuilder.append(STAR_RATING.name).append(":").append(getStarRating()).append("\n");
stringBuilder.append(IMPRESSION_TRACKER.name).append(":").append(getImpressionTrackers()).append("\n");
stringBuilder.append(CLICK_TRACKER.name).append(":").append(mMoPubClickTracker).append("\n");
stringBuilder.append(CLICK_DESTINATION.name).append(":").append(getClickDestinationUrl()).append("\n");
stringBuilder.append(CALL_TO_ACTION.name).append(":").append(getCallToAction()).append("\n");
stringBuilder.append("recordedImpression").append(":").append(mRecordedImpression).append("\n");
stringBuilder.append("extras").append(":").append(getExtras());
return stringBuilder.toString();
}
@NonNull
public String getAdUnitId() {
return mAdUnitId;
}
// Interface Methods
// Getters
@Nullable
public String getMainImageUrl() {
return mNativeAd.getMainImageUrl();
}
@Nullable
public String getIconImageUrl() {
return mNativeAd.getIconImageUrl();
}
@Nullable
public String getClickDestinationUrl() {
return mNativeAd.getClickDestinationUrl();
}
@Nullable
public String getCallToAction() {
return mNativeAd.getCallToAction();
}
@Nullable
public String getTitle() {
return mNativeAd.getTitle();
}
@Nullable
public String getText() {
return mNativeAd.getText();
}
@NonNull
public List<String> getImpressionTrackers() {
final Set<String> allImpressionTrackers = new HashSet<String>();
allImpressionTrackers.addAll(mMoPubImpressionTrackers);
allImpressionTrackers.addAll(mNativeAd.getImpressionTrackers());
return new ArrayList<String>(allImpressionTrackers);
}
@NonNull
public String getClickTracker() {
return mMoPubClickTracker;
}
@Nullable
public Double getStarRating() {
return mNativeAd.getStarRating();
}
public int getImpressionMinTimeViewed() {
return mNativeAd.getImpressionMinTimeViewed();
}
public int getImpressionMinPercentageViewed() {
return mNativeAd.getImpressionMinPercentageViewed();
}
// Extras Getters
@Nullable
public Object getExtra(final String key) {
return mNativeAd.getExtra(key);
}
@NonNull
public Map<String, Object> getExtras() {
return mNativeAd.getExtras();
}
public boolean isOverridingImpressionTracker() {
return mNativeAd.isOverridingImpressionTracker();
}
public boolean isOverridingClickTracker() {
return mNativeAd.isOverridingClickTracker();
}
// Event Handlers
public void prepare(@NonNull final View view) {
if (isDestroyed()) {
return;
}
if (!isOverridingClickTracker()) {
setOnClickListener(view, new NativeViewClickListener());
}
mNativeAd.prepare(view);
}
public void recordImpression(@Nullable final View view) {
if (getRecordedImpression() || isDestroyed()) {
return;
}
for (final String impressionTracker : getImpressionTrackers()) {
TrackingRequest.makeTrackingHttpRequest(
impressionTracker, mContext, MoPubEvents.Type.IMPRESSION_REQUEST);
}
mNativeAd.recordImpression();
mRecordedImpression = true;
mMoPubNativeEventListener.onNativeImpression(view);
}
public void handleClick(@Nullable final View view) {
if (isDestroyed()) {
return;
}
if (!isClicked()) {
TrackingRequest.makeTrackingHttpRequest(
mMoPubClickTracker, mContext, MoPubEvents.Type.CLICK_REQUEST);
}
openClickDestinationUrl(view);
mNativeAd.handleClick(view);
mIsClicked = true;
mMoPubNativeEventListener.onNativeClick(view);
}
public void clear(@NonNull final View view) {
setOnClickListener(view, null);
mNativeAd.clear(view);
}
public void destroy() {
if (isDestroyed()) {
return;
}
mMoPubNativeEventListener = MoPubNative.EMPTY_EVENT_LISTENER;
mNativeAd.destroy();
mIsDestroyed = true;
}
// Non Interface Public Methods
public void loadMainImage(@Nullable final ImageView imageView) {
loadImageView(getMainImageUrl(), imageView);
}
public void loadIconImage(@Nullable final ImageView imageView) {
loadImageView(getIconImageUrl(), imageView);
}
public void loadExtrasImage(final String key, final ImageView imageView) {
final Object object = getExtra(key);
if (object != null && object instanceof String) {
loadImageView((String) object, imageView);
}
}
public boolean getRecordedImpression() {
return mRecordedImpression;
}
public boolean isClicked() {
return mIsClicked;
}
public boolean isDestroyed() {
return mIsDestroyed;
}
// Helpers
private void loadImageView(@Nullable final String url, @Nullable final ImageView imageView) {
if (imageView == null) {
return;
}
if (url == null) {
imageView.setImageDrawable(null);
} else {
mImageLoader.get(url, new ImageLoader.ImageListener() {
@Override
public void onResponse(final ImageLoader.ImageContainer imageContainer,
final boolean isImmediate) {
if (!isImmediate) {
MoPubLog.d("Image was not loaded immediately into your ad view. You should call preCacheImages as part of your custom event loading process.");
}
imageView.setImageBitmap(imageContainer.getBitmap());
}
@Override
public void onErrorResponse(final VolleyError volleyError) {
MoPubLog.d("Failed to load image.", volleyError);
imageView.setImageDrawable(null);
}
});
}
}
private void openClickDestinationUrl(@Nullable final View view) {
if (getClickDestinationUrl() == null) {
return;
}
SpinningProgressView spinningProgressView = null;
if (view != null) {
spinningProgressView = new SpinningProgressView(mContext);
spinningProgressView.addToRoot(view);
}
final Iterator<String> urlIterator = Arrays.asList(getClickDestinationUrl()).iterator();
final ClickDestinationResolutionListener urlResolutionListener =
new ClickDestinationResolutionListener(mContext, urlIterator, spinningProgressView);
UrlResolutionTask.getResolvedUrl(urlIterator.next(), urlResolutionListener);
}
private void setOnClickListener(@NonNull final View view,
@Nullable final OnClickListener onClickListener) {
view.setOnClickListener(onClickListener);
if ((view instanceof ViewGroup)) {
ViewGroup viewGroup = (ViewGroup)view;
for (int i = 0; i < viewGroup.getChildCount(); i++)
setOnClickListener(viewGroup.getChildAt(i), onClickListener);
}
}
@VisibleForTesting
class NativeViewClickListener implements OnClickListener {
@Override
public void onClick(@NonNull final View view) {
handleClick(view);
}
}
@Nullable
@Deprecated
public String getSubtitle() {
return mNativeAd.getText();
}
@NonNull
@VisibleForTesting
@Deprecated
MoPubNativeEventListener getMoPubNativeEventListener() {
return mMoPubNativeEventListener;
}
@VisibleForTesting
@Deprecated
void setRecordedImpression(final boolean recordedImpression) {
mRecordedImpression = recordedImpression;
}
}