diff --git a/android/src/com/mapswithme/maps/ads/AdTracker.java b/android/src/com/mapswithme/maps/ads/AdTracker.java index fb02094816..e4163e979b 100644 --- a/android/src/com/mapswithme/maps/ads/AdTracker.java +++ b/android/src/com/mapswithme/maps/ads/AdTracker.java @@ -2,7 +2,7 @@ package com.mapswithme.maps.ads; import android.support.annotation.NonNull; -public interface AdTracker +interface AdTracker { void onViewShown(@NonNull String bannerId); void onViewHidden(@NonNull String bannerId); diff --git a/android/src/com/mapswithme/maps/ads/DefaultAdTracker.java b/android/src/com/mapswithme/maps/ads/DefaultAdTracker.java index 703954506a..31956742cc 100644 --- a/android/src/com/mapswithme/maps/ads/DefaultAdTracker.java +++ b/android/src/com/mapswithme/maps/ads/DefaultAdTracker.java @@ -13,7 +13,7 @@ public class DefaultAdTracker implements AdTracker, OnAdCacheModifiedListener { private final static Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.MISC); private final static String TAG = DefaultAdTracker.class.getSimpleName(); - private final static int GOOD_IMPRESSION_TIME_MS = 2000; + private final static int IMPRESSION_TIME_MS = 2000; private final Map mTracks = new HashMap<>(); @Override @@ -21,8 +21,12 @@ public class DefaultAdTracker implements AdTracker, OnAdCacheModifiedListener { LOGGER.d(TAG, "onViewShown bannerId = " + bannerId); TrackInfo info = mTracks.get(bannerId); - if (info != null) - info.setVisible(true); + if (info == null) + { + info = new TrackInfo(); + mTracks.put(bannerId, info); + } + info.setVisible(true); } @Override @@ -30,8 +34,10 @@ public class DefaultAdTracker implements AdTracker, OnAdCacheModifiedListener { LOGGER.d(TAG, "onViewHidden bannerId = " + bannerId); TrackInfo info = mTracks.get(bannerId); - if (info != null) - info.setVisible(false); + if (info == null) + throw new AssertionError("A track info cannot be null because this method " + + "is called only after onViewShown!"); + info.setVisible(false); } @Override @@ -49,25 +55,34 @@ public class DefaultAdTracker implements AdTracker, OnAdCacheModifiedListener public boolean isImpressionGood(@NonNull String bannerId) { TrackInfo info = mTracks.get(bannerId); - return info != null && info.getShowTime() > GOOD_IMPRESSION_TIME_MS; + return info != null && info.getShowTime() > IMPRESSION_TIME_MS; } @Override public void onRemoved(@NonNull String id) { - LOGGER.d(TAG, "onRemoved id = " + id); mTracks.remove(id); } @Override public void onPut(@NonNull String id) { - LOGGER.d(TAG, "onPut id = " + id); - mTracks.put(id, new TrackInfo()); + TrackInfo info = mTracks.get(id); + if (info == null) + { + mTracks.put(id, new TrackInfo()); + return; + } + + if (info.getShowTime() != 0) + info.setLastShow(true); } private static class TrackInfo { + /** + * A timestamp to track ad visibility + */ private long mTimestamp; /** * Accumulates amount of time that ad is already shown. @@ -82,44 +97,63 @@ public class DefaultAdTracker implements AdTracker, OnAdCacheModifiedListener */ private boolean mFilled; - public void setVisible(boolean visible) + /** + * Indicates whether it's the last time when an ad was shown or not. + */ + private boolean mLastShow; + + void setVisible(boolean visible) { + boolean wasVisible = mVisible; + mVisible = visible; + // No need tracking if the ad is not filled with a content if (!mFilled) return; // If ad becomes visible, and it's filled with a content the timestamp must be stored. - if (visible && !mVisible) + if (visible && !wasVisible) { mTimestamp = SystemClock.elapsedRealtime(); } // If ad is hidden the show time must be accumulated. - else if (!visible && mVisible) + else if (!visible && wasVisible) { + if (mLastShow) + { + mShowTime = 0; + mTimestamp = 0; + mLastShow = false; + LOGGER.d(TAG, "it's a last time for this ad"); + return; + } mShowTime += SystemClock.elapsedRealtime() - mTimestamp; mTimestamp = 0; } - mVisible = visible; + } + + boolean isVisible() + { + return mVisible; } public void fill() { // If the visible ad is filled with the content the timestamp must be stored if (mVisible) - { mTimestamp = SystemClock.elapsedRealtime(); - } - mFilled = true; - } - private boolean isRealShow() - { - return mFilled && mVisible; + mFilled = true; } long getShowTime() { return mShowTime; } + + void setLastShow(boolean lastShow) + { + mLastShow = lastShow; + } } } diff --git a/android/src/com/mapswithme/maps/ads/FacebookAdsLoader.java b/android/src/com/mapswithme/maps/ads/FacebookAdsLoader.java index db0fe081c3..0c7610924d 100644 --- a/android/src/com/mapswithme/maps/ads/FacebookAdsLoader.java +++ b/android/src/com/mapswithme/maps/ads/FacebookAdsLoader.java @@ -47,7 +47,7 @@ public class FacebookAdsLoader implements AdListener * @param tracker An ad tracker */ @UiThread - public void load(@NonNull Context context, @NonNull String placementId, @NonNull AdTracker tracker) + public void load(@NonNull Context context, @NonNull String placementId, @Nullable AdTracker tracker) { LOGGER.d(TAG, "Load a facebook ad for a placement id '" + placementId + "'"); @@ -60,7 +60,7 @@ public class FacebookAdsLoader implements AdListener return; } - if (tracker.isImpressionGood(placementId) + if (tracker != null && tracker.isImpressionGood(placementId) && SystemClock.elapsedRealtime() - cachedAd.getLoadedTime() >= REQUEST_INTERVAL_MS) { LOGGER.d(TAG, "A new ad will be loaded because the previous one has a good impression"); @@ -204,7 +204,7 @@ public class FacebookAdsLoader implements AdListener private static class FacebookAd { @NonNull - private NativeAd mAd; + private final NativeAd mAd; private final long mLoadedTime; FacebookAd(@NonNull NativeAd ad, long timestamp) diff --git a/android/src/com/mapswithme/maps/widget/placepage/BannerController.java b/android/src/com/mapswithme/maps/widget/placepage/BannerController.java index b8be02d496..342a5400c5 100644 --- a/android/src/com/mapswithme/maps/widget/placepage/BannerController.java +++ b/android/src/com/mapswithme/maps/widget/placepage/BannerController.java @@ -90,7 +90,6 @@ final class BannerController mActionSmall = (TextView) bannerView.findViewById(R.id.tv__action_small); mActionLarge = (TextView) bannerView.findViewById(R.id.tv__action_large); mAds = bannerView.findViewById(R.id.tv__ads); - //TODO: pass as constructor arguments mAdsLoader = new FacebookAdsLoader(); mAdsLoader.setAdsListener(new NativeAdsListener()); mAdTracker = new DefaultAdTracker(); @@ -156,12 +155,11 @@ final class BannerController void open() { - if (!isBannerVisible() || mBanner == null || mOpened) + if (!isBannerVisible() || mBanner == null || TextUtils.isEmpty(mBanner.getId()) || mOpened) return; mOpened = true; setFrameHeight(WRAP_CONTENT); - //FIXME NPE NativeAd data = mAdsLoader.getAdByIdFromCache(mBanner.getId()); if (data != null) loadIcon(data.getAdIcon());