diff --git a/README.md b/README.md index f4e560c..2a50b67 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,15 @@ Admob Adapter ====================== +The reference to the [DOCUMENTATION](https://github.com/clockbyte/admobadapter/wiki/Cookbook) for people who are in hurry! + Admob Adapter is an Android library that makes it easy to integrate [Admob native ads](https://firebase.google.com/docs/admob/android/native) (both Express and Advanced) into ```ListView/RecyclerView``` in the way that is shown in the following image/animation. ![](https://raw.githubusercontent.com/clockbyte/admobadapter/master/screenshots/device-2015-08-28-012121.png) ![](https://raw.githubusercontent.com/clockbyte/admobadapter/master/screenshots/ezgif.com-gif-maker.gif "Demo gif") -#Main features - -* Publish of the native ads without changing the logic of your ```Adapter``` -* Customization: you can easily set the maximum count of ads per list, the count of items shown between ad blocks and a custom layouts for ads blocks. -* Easy to update ad blocks periodically - -The admobadapter-sampleapp shows the available features and customizations. - -# Installation - -##Cloning -First of all you will have to clone the library. -```shell -git clone https://github.com/clockbyte/admobadapter.git -``` - -Now that you have the library you will have to import it into Android Studio. -In Android Studio navigate the menus like this. -``` -File -> Import Project ... -``` -In the following dialog navigate to ```admobadapter-master``` which you cloned to your computer in the previous steps and select the `build.gradle`. - -##Or -you also can simply copy all the *.java from -``` -admobadapter/admobadapter/src/main/java/com/clockbyte/admobadapter/ -``` -to your ```java``` sources folder (feel free to edit the package names in all files but please leave the License header as is). - -and all the *.xml from -``` -admobadapter/admobadapter/src/main/res/layout/ -``` -to your ```res/layout``` folder. -Also please don't forget to copy the string resource ```test_admob_unit_id``` from ```admobadapter/admobadapter/src/main/res/values/strings.xml``` to your ```strings.xml``` file. Then kindly use it as demonstrated in the sampleapp demo. -When you'll be ready to deploy your app to Release you'll have to register in the Admob and create Ad unit ID there. Then you'd kindly replace the ```test_admob_unit_id``` with your real Ad unit ID. And please don't forget to use the test ID instead of real one when you're debugging/testing your app otherwise Admob can ban your account (artificial inflating of impressions and so on). - -#Base usage -The quick and dirty start is shown in the sampleapp of the project (to switch the sample between the RecyclerView and ListView examples kindly edit the ```AndroidManifest.xml```) - -The Developer's guide on native ads could be found [here](https://developers.google.com/admob/android/native). - -The cook recipes could be found in the [Wiki](https://github.com/clockbyte/admobadapter/wiki/Cookbook) - -Also feel free to ask me. +You can read the rest info (main features, installation, base usage and so on) at the [project's home page](https://github.com/clockbyte/admobadapter/wiki/Home) if you wish. #Contributions Contributions are very welcome. If you find a bug in the library or want an improvement and feel you can work on it yourself, fork + pull request and i'll appreciate it much! diff --git a/admobadapter/build.gradle b/admobadapter/build.gradle index 8979ef8..2012f99 100644 --- a/admobadapter/build.gradle +++ b/admobadapter/build.gradle @@ -17,7 +17,7 @@ android { buildToolsVersion "23.0.3" defaultConfig { - minSdkVersion 9 + minSdkVersion 11 targetSdkVersion 22 versionCode 1 versionName "1.0" diff --git a/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterCalculator.java b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterCalculator.java new file mode 100644 index 0000000..b0cb4c1 --- /dev/null +++ b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterCalculator.java @@ -0,0 +1,166 @@ +/* + * Copyright 2015 Yahoo Inc. All rights reserved. + * Copyright 2016 Clockbyte LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.clockbyte.admobadapter; + +import android.util.Log; + +public class AdmobAdapterCalculator { + + protected AdmobAdapterWrapperInterface mAdmobAdapter; + + public AdmobAdapterCalculator(AdmobAdapterWrapperInterface admobAdapter){ + mAdmobAdapter = admobAdapter; + } + + protected int mNoOfDataBetweenAds; + /* + * Gets the number of your data items between ad blocks, by default it equals to 10. + * You should set it according to the Admob's policies and rules which says not to + * display more than one ad block at the visible part of the screen + * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices + */ + public int getNoOfDataBetweenAds() { + return mNoOfDataBetweenAds; + } + + /* + * Sets the number of your data items between ad blocks, by default it equals to 10. + * You should set it according to the Admob's policies and rules which says not to + * display more than one ad block at the visible part of the screen + * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices + */ + public void setNoOfDataBetweenAds(int mNoOfDataBetweenAds) { + this.mNoOfDataBetweenAds = mNoOfDataBetweenAds; + } + + protected int firstAdIndex = 0; + + public int getFirstAdIndex() { + return firstAdIndex; + } + + /* + * Sets the first ad block index (zero-based) in the adapter, by default it equals to 0 + */ + public void setFirstAdIndex(int firstAdIndex) { + this.firstAdIndex = firstAdIndex; + } + + protected int mLimitOfAds; + + /* + * Gets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) + */ + public int getLimitOfAds() { + return mLimitOfAds; + } + + /* + * Sets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) + */ + public void setLimitOfAds(int mLimitOfAds) { + this.mLimitOfAds = mLimitOfAds; + } + + + public int getAdsCountToPublish(){ + //int cntFetched = adFetcher.getFetchedAdsCount(); + //if(cntFetched == 0) return 0; + int expected = 0; + if(mAdmobAdapter.getAdapterCount() > 0 && mAdmobAdapter.getAdapterCount()>= getOffsetValue()+1) + expected = (mAdmobAdapter.getAdapterCount() - getOffsetValue()) / getNoOfDataBetweenAds() + 1; + expected = Math.max(0, expected); + //int noOfAds = Math.min(cntFetched, expected); + return Math.min(expected, getLimitOfAds()); + } + + /** + * Translates an adapter position to an actual position within the underlying dataset. + * + * @param position the adapter position + * @return the original position that the adapter position would have been without ads + */ + public int getOriginalContentPosition(int position) { + int noOfAds = getAdsCountToPublish(); + // No of spaces for ads in the dataset, according to ad placement rules + int adSpacesCount = (getAdIndex(position) + 1); + int originalPosition = position - Math.min(adSpacesCount, noOfAds); + Log.d("POSITION", position + " is originally " + originalPosition); + + return originalPosition; + } + + /** + * Determines if an ad can be shown at the given position. Checks if the position is for + * an ad, using the preconfigured ad positioning rules; and if a native ad object is + * available to place in that position. + * + * @param position the adapter position + * @return true if ads can + */ + public boolean canShowAdAtPosition(int position) { + + // Is this a valid position for an ad? + // Is an ad for this position available? + return isAdPosition(position) && isAdAvailable(position); + } + + /** + * Gets the ad index for this adapter position within the list of currently fetched ads. + * + * @param position the adapter position + * @return the index of the ad within the list of fetched ads + */ + public int getAdIndex(int position) { + int index = -1; + if(position >= getOffsetValue()) + index = (position - getOffsetValue()) / (getNoOfDataBetweenAds()+1); + Log.d("POSITION", "index " + index + " for position " + position); + return index; + } + + /** + * Checks if adapter position is an ad position. + * + * @param position the adapter position + * @return {@code true} if an ad position, {@code false} otherwise + */ + public boolean isAdPosition(int position) { + int result = (position - getOffsetValue()) % (getNoOfDataBetweenAds() + 1); + return result == 0; + } + + public int getOffsetValue() { + return getFirstAdIndex() > 0 ? getFirstAdIndex() : 0; + } + + /** + * Checks if an ad is available for this position. + * + * @param position the adapter position + * @return {@code true} if an ad is available, {@code false} otherwise + */ + public boolean isAdAvailable(int position) { + int adIndex = getAdIndex(position); + int firstAdPos = getOffsetValue(); + + return position >= firstAdPos && adIndex >= 0 && adIndex < getLimitOfAds(); + } + + +} diff --git a/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterWrapper.java b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterWrapper.java index 5e0e347..26b2265 100644 --- a/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterWrapper.java +++ b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterWrapper.java @@ -19,6 +19,7 @@ import android.content.Context; import android.database.DataSetObserver; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -32,7 +33,7 @@ * Adapter that has common functionality for any adapters that need to show ads in-between * other data. */ -public class AdmobAdapterWrapper extends BaseAdapter implements AdmobFetcherBase.AdmobListener { +public class AdmobAdapterWrapper extends BaseAdapter implements AdmobFetcherBase.AdmobListener, AdmobAdapterWrapperInterface { private final String TAG = AdmobAdapterWrapper.class.getCanonicalName(); @@ -59,6 +60,17 @@ public void onInvalidated() { AdmobFetcher adFetcher; Context mContext; + private AdmobAdapterCalculator AdapterCalculator = new AdmobAdapterCalculator(this); + /* + * Gets an object which incapsulates transformation of the source and ad blocks indices + */ + public AdmobAdapterCalculator getAdapterCalculator(){return AdapterCalculator;} + /* +* Injects an object which incapsulates transformation of the source and ad blocks indices. You could override calculations +* by inheritance of AdmobAdapterCalculator class +*/ + public void setAdapterCalculator(AdmobAdapterCalculator adapterCalculatordmob){AdapterCalculator = adapterCalculatordmob;} + private static final int VIEW_TYPE_COUNT = 2; private static final int VIEW_TYPE_AD_CONTENT = 1; @@ -67,8 +79,6 @@ public void onInvalidated() { private final static int DEFAULT_NO_OF_DATA_BETWEEN_ADS = 10; private final static int DEFAULT_LIMIT_OF_ADS = 3; - private int mNoOfDataBetweenAds; - /* * Gets the number of your data items between ad blocks, by default it equals to 10. * You should set it according to the Admob's policies and rules which says not to @@ -76,9 +86,8 @@ public void onInvalidated() { * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices */ public int getNoOfDataBetweenAds() { - return mNoOfDataBetweenAds; + return AdapterCalculator.getNoOfDataBetweenAds(); } - /* * Sets the number of your data items between ad blocks, by default it equals to 10. * You should set it according to the Admob's policies and rules which says not to @@ -86,23 +95,31 @@ public int getNoOfDataBetweenAds() { * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices */ public void setNoOfDataBetweenAds(int mNoOfDataBetweenAds) { - this.mNoOfDataBetweenAds = mNoOfDataBetweenAds; + AdapterCalculator.setNoOfDataBetweenAds(mNoOfDataBetweenAds); } - private int mLimitOfAds; + public int getFirstAdIndex() { + return AdapterCalculator.getFirstAdIndex(); + } + /* + * Sets the first ad block index (zero-based) in the adapter, by default it equals to 0 + */ + public void setFirstAdIndex(int firstAdIndex) { + AdapterCalculator.setFirstAdIndex(firstAdIndex); + } /* * Gets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) */ public int getLimitOfAds() { - return mLimitOfAds; + return AdapterCalculator.getLimitOfAds(); } /* * Sets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) */ public void setLimitOfAds(int mLimitOfAds) { - this.mLimitOfAds = mLimitOfAds; + AdapterCalculator.setLimitOfAds(mLimitOfAds); } private int mContentAdsLayoutId; @@ -138,10 +155,18 @@ public void setInstallAdsLayoutId(int mInstallAdsLayoutId) { } /* - *Sets a test device ID. Normally you don't have to set it + *Add a test device ID. */ + public void addTestDeviceId(String testDeviceId) { + adFetcher.addTestDeviceId(testDeviceId); + } + + /* +*Sets a test device ID. Normally you don't have to set it +*/ + @Deprecated public void setTestDeviceId(String testDeviceId) { - adFetcher.setTestDeviceId(testDeviceId); + adFetcher.addTestDeviceId(testDeviceId); } /* @@ -191,7 +216,7 @@ public View getView(int position, View convertView, ViewGroup parent) { } return lvi2; default: - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getView(origPos, convertView, parent); } } @@ -238,19 +263,13 @@ public int getCount() { No of currently fetched ads, as long as it isn't more than no of max ads that can fit dataset. */ - int noOfAds = getAdsCountToPublish(); + int noOfAds = AdapterCalculator.getAdsCountToPublish(); return mAdapter.getCount() > 0 ? mAdapter.getCount() + noOfAds : 0; } else { return 0; } } - public int getAdsCountToPublish(){ - int noOfAds = Math.min(adFetcher.getFetchedAdsCount(), - mAdapter.getCount() / getNoOfDataBetweenAds()); - return Math.min(noOfAds, getLimitOfAds()); - } - /** * Gets the item in a given position in the dataset. If an ad is to be returned, * a {@link NativeAd} object is returned. @@ -261,11 +280,11 @@ public int getAdsCountToPublish(){ @Override public Object getItem(int position) { - if (canShowAdAtPosition(position)) { - int adPos = getAdIndex(position); + if (AdapterCalculator.canShowAdAtPosition(position)) { + int adPos = AdapterCalculator.getAdIndex(position); return adFetcher.getAdForIndex(adPos); } else { - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getItem(origPos); } } @@ -282,78 +301,16 @@ public int getViewTypeCount() { @Override public int getItemViewType(int position) { - if (canShowAdAtPosition(position)) { - int adPos = getAdIndex(position); + if (AdapterCalculator.canShowAdAtPosition(position)) { + int adPos = AdapterCalculator.getAdIndex(position); NativeAd ad = adFetcher.getAdForIndex(adPos); return ad instanceof NativeAppInstallAd ? VIEW_TYPE_AD_INSTALL : VIEW_TYPE_AD_CONTENT; } else { - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getItemViewType(origPos); } } - /** - * Translates an adapter position to an actual position within the underlying dataset. - * - * @param position the adapter position - * @return the original position that the adapter position would have been without ads - */ - protected int getOriginalContentPosition(int position) { - int noOfAds = getAdsCountToPublish(); - // No of spaces for ads in the dataset, according to ad placement rules - int adSpacesCount = position / (getNoOfDataBetweenAds() + 1); - return position - Math.min(adSpacesCount, noOfAds); - } - - /** - * Determines if an ad can be shown at the given position. Checks if the position is for - * an ad, using the preconfigured ad positioning rules; and if a native ad object is - * available to place in that position. - * - * @param position the adapter position - * @return true if ads can - */ - protected boolean canShowAdAtPosition(int position) { - - // Is this a valid position for an ad? - // Is an ad for this position available? - return isAdPosition(position) && isAdAvailable(position); - } - - /** - * Gets the ad index for this adapter position within the list of currently fetched ads. - * - * @param position the adapter position - * @return the index of the ad within the list of fetched ads - */ - private int getAdIndex(int position) { - return (position / getNoOfDataBetweenAds()) - 1; - } - - /** - * Checks if adapter position is an ad position. - * - * @param position the adapter position - * @return {@code true} if an ad position, {@code false} otherwise - */ - private boolean isAdPosition(int position) { - return (position + 1) % (getNoOfDataBetweenAds() + 1) == 0; - } - - /** - * Checks if an ad is available for this position. - * - * @param position the adapter position - * @return {@code true} if an ad is available, {@code false} otherwise - */ - private boolean isAdAvailable(int position) { - int adIndex = getAdIndex(position); - return position >= getNoOfDataBetweenAds() - && adIndex >= 0 - && adIndex < getLimitOfAds() - && adFetcher.getFetchedAdsCount() > adIndex; - } - /** * Destroys all currently fetched ads */ @@ -373,4 +330,9 @@ public void onAdCountChanged() { notifyDataSetChanged(); } + + @Override + public int getAdapterCount() { + return mAdapter.getCount(); + } } diff --git a/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterWrapperInterface.java b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterWrapperInterface.java new file mode 100644 index 0000000..9a560d6 --- /dev/null +++ b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobAdapterWrapperInterface.java @@ -0,0 +1,8 @@ +package com.clockbyte.admobadapter; + +/** + * Created by FILM on 06.07.2016. + */ +public interface AdmobAdapterWrapperInterface { + int getAdapterCount(); +} diff --git a/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobFetcherBase.java b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobFetcherBase.java index 86b6d86..f118d30 100644 --- a/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobFetcherBase.java +++ b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobFetcherBase.java @@ -62,18 +62,18 @@ public void setAdmobReleaseUnitId(String admobReleaseUnitId) { this.admobReleaseUnitId = admobReleaseUnitId; } - protected String testDeviceId; + protected ArrayList testDeviceId = new ArrayList(); /* *Gets a test device ID. Normally you don't have to set it */ - public String getTestDeviceId() { + public ArrayList getTestDeviceIds() { return testDeviceId; } /* *Sets a test device ID. Normally you don't have to set it */ - public void setTestDeviceId(String testDeviceId) { - this.testDeviceId = testDeviceId; + public void addTestDeviceId(String testDeviceId) { + this.testDeviceId.add(testDeviceId); } /** @@ -133,11 +133,10 @@ protected void notifyObserversOfAdSizeChange() { */ protected synchronized AdRequest getAdRequest() { AdRequest.Builder adBldr = new AdRequest.Builder(); - if(!TextUtils.isEmpty(getTestDeviceId())) - adBldr.addTestDevice(getTestDeviceId()); + for (String id : getTestDeviceIds()) { + adBldr.addTestDevice(id); + } return adBldr.build(); - //.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); - // All emulators are added by default as test devices } /** diff --git a/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobRecyclerAdapterWrapper.java b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobRecyclerAdapterWrapper.java index e2eef57..b82cc46 100644 --- a/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobRecyclerAdapterWrapper.java +++ b/admobadapter/src/main/java/com/clockbyte/admobadapter/AdmobRecyclerAdapterWrapper.java @@ -19,6 +19,7 @@ import android.content.Context; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -33,7 +34,7 @@ */ public class AdmobRecyclerAdapterWrapper extends RecyclerView.Adapter> - implements AdmobFetcherBase.AdmobListener { + implements AdmobFetcherBase.AdmobListener, AdmobAdapterWrapperInterface { private final String TAG = AdmobRecyclerAdapterWrapper.class.getCanonicalName(); @@ -56,6 +57,17 @@ public void onChanged() { AdmobFetcher adFetcher; Context mContext; + private AdmobAdapterCalculator AdapterCalculator = new AdmobAdapterCalculator(this); + /* + * Gets an object which incapsulates transformation of the source and ad blocks indices + */ + public AdmobAdapterCalculator getAdapterCalculator(){return AdapterCalculator;} + /* +* Injects an object which incapsulates transformation of the source and ad blocks indices. You could override calculations +* by inheritance of AdmobAdapterCalculator class +*/ + public void setAdapterCalculator(AdmobAdapterCalculator adapterCalculatordmob){AdapterCalculator = adapterCalculatordmob;} + private static final int VIEW_TYPE_COUNT = 2; private static final int VIEW_TYPE_AD_CONTENT = 1; @@ -64,18 +76,15 @@ public void onChanged() { private final static int DEFAULT_NO_OF_DATA_BETWEEN_ADS = 10; private final static int DEFAULT_LIMIT_OF_ADS = 3; - private int mNoOfDataBetweenAds; - /* - * Gets the number of your data items between ad blocks, by default it equals to 10. - * You should set it according to the Admob's policies and rules which says not to - * display more than one ad block at the visible part of the screen - * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices - */ + * Gets the number of your data items between ad blocks, by default it equals to 10. + * You should set it according to the Admob's policies and rules which says not to + * display more than one ad block at the visible part of the screen + * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices + */ public int getNoOfDataBetweenAds() { - return mNoOfDataBetweenAds; + return AdapterCalculator.getNoOfDataBetweenAds(); } - /* * Sets the number of your data items between ad blocks, by default it equals to 10. * You should set it according to the Admob's policies and rules which says not to @@ -83,23 +92,31 @@ public int getNoOfDataBetweenAds() { * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices */ public void setNoOfDataBetweenAds(int mNoOfDataBetweenAds) { - this.mNoOfDataBetweenAds = mNoOfDataBetweenAds; + AdapterCalculator.setNoOfDataBetweenAds(mNoOfDataBetweenAds); } - private int mLimitOfAds; + public int getFirstAdIndex() { + return AdapterCalculator.getFirstAdIndex(); + } + /* + * Sets the first ad block index (zero-based) in the adapter, by default it equals to 0 + */ + public void setFirstAdIndex(int firstAdIndex) { + AdapterCalculator.setFirstAdIndex(firstAdIndex); + } /* * Gets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) */ public int getLimitOfAds() { - return mLimitOfAds; + return AdapterCalculator.getLimitOfAds(); } /* * Sets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) */ public void setLimitOfAds(int mLimitOfAds) { - this.mLimitOfAds = mLimitOfAds; + AdapterCalculator.setLimitOfAds(mLimitOfAds); } private int mContentAdsLayoutId; @@ -135,10 +152,17 @@ public void setInstallAdsLayoutId(int mInstallAdsLayoutId) { } /* - *Sets a test device ID. Normally you don't have to set it + *Add a test device ID. */ + public void addTestDeviceId(String testDeviceId) { + adFetcher.addTestDeviceId(testDeviceId); + } + /* +*Sets a test device ID. Normally you don't have to set it +*/ + @Deprecated public void setTestDeviceId(String testDeviceId) { - adFetcher.setTestDeviceId(testDeviceId); + adFetcher.addTestDeviceId(testDeviceId); } /* @@ -180,7 +204,7 @@ public void onBindViewHolder(ViewWrapper viewHolder, int position) { AdViewHelper.bindContentAdView(lvi2, ad2); break; default: - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); mAdapter.onBindViewHolder(viewHolder, origPos); } } @@ -251,20 +275,14 @@ public int getItemCount() { No of currently fetched ads, as long as it isn't more than no of max ads that can fit dataset. */ - int noOfAds = getAdsCountToPublish(); + int noOfAds = AdapterCalculator.getAdsCountToPublish(); return mAdapter.getItemCount() > 0 ? mAdapter.getItemCount() + noOfAds : 0; } else { return 0; } } - public int getAdsCountToPublish(){ - int noOfAds = Math.min(adFetcher.getFetchedAdsCount(), - mAdapter.getItemCount() / getNoOfDataBetweenAds()); - return Math.min(noOfAds, getLimitOfAds()); - } - - /** + /** * Gets the item in a given position in the dataset. If an ad is to be returned, * a {@link NativeAd} object is returned. * @@ -273,11 +291,11 @@ public int getAdsCountToPublish(){ */ public Object getItem(int position) { - if (canShowAdAtPosition(position)) { - int adPos = getAdIndex(position); + if (AdapterCalculator.canShowAdAtPosition(position)) { + int adPos = AdapterCalculator.getAdIndex(position); return adFetcher.getAdForIndex(adPos); } else { - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getItem(origPos); } } @@ -289,78 +307,16 @@ public long getItemId(int position) { @Override public int getItemViewType(int position) { - if (canShowAdAtPosition(position)) { - int adPos = getAdIndex(position); + if (AdapterCalculator.canShowAdAtPosition(position)) { + int adPos = AdapterCalculator.getAdIndex(position); NativeAd ad = adFetcher.getAdForIndex(adPos); return ad instanceof NativeAppInstallAd ? VIEW_TYPE_AD_INSTALL : VIEW_TYPE_AD_CONTENT; } else { - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getItemViewType(origPos); } } - /** - * Translates an adapter position to an actual position within the underlying dataset. - * - * @param position the adapter position - * @return the original position that the adapter position would have been without ads - */ - protected int getOriginalContentPosition(int position) { - int noOfAds = getAdsCountToPublish(); - // No of spaces for ads in the dataset, according to ad placement rules - int adSpacesCount = position / (getNoOfDataBetweenAds() + 1); - return position - Math.min(adSpacesCount, noOfAds); - } - - /** - * Determines if an ad can be shown at the given position. Checks if the position is for - * an ad, using the preconfigured ad positioning rules; and if a native ad object is - * available to place in that position. - * - * @param position the adapter position - * @return true if ads can - */ - protected boolean canShowAdAtPosition(int position) { - - // Is this a valid position for an ad? - // Is an ad for this position available? - return isAdPosition(position) && isAdAvailable(position); - } - - /** - * Gets the ad index for this adapter position within the list of currently fetched ads. - * - * @param position the adapter position - * @return the index of the ad within the list of fetched ads - */ - private int getAdIndex(int position) { - return (position / getNoOfDataBetweenAds()) - 1; - } - - /** - * Checks if adapter position is an ad position. - * - * @param position the adapter position - * @return {@code true} if an ad position, {@code false} otherwise - */ - private boolean isAdPosition(int position) { - return (position + 1) % (getNoOfDataBetweenAds() + 1) == 0; - } - - /** - * Checks if an ad is available for this position. - * - * @param position the adapter position - * @return {@code true} if an ad is available, {@code false} otherwise - */ - private boolean isAdAvailable(int position) { - int adIndex = getAdIndex(position); - return position >= getNoOfDataBetweenAds() - && adIndex >= 0 - && adIndex < getLimitOfAds() - && adFetcher.getFetchedAdsCount() > adIndex; - } - /** * Destroys all currently fetched ads */ @@ -380,4 +336,9 @@ public void onAdCountChanged() { notifyDataSetChanged(); } + + @Override + public int getAdapterCount() { + return mAdapter.getItemCount(); + } } diff --git a/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobExpressAdapterWrapper.java b/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobExpressAdapterWrapper.java index e864d4e..df3e0a2 100644 --- a/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobExpressAdapterWrapper.java +++ b/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobExpressAdapterWrapper.java @@ -19,20 +19,26 @@ import android.content.Context; import android.database.DataSetObserver; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AbsListView; import android.widget.BaseAdapter; +import com.clockbyte.admobadapter.AdmobAdapterCalculator; +import com.clockbyte.admobadapter.AdmobAdapterWrapperInterface; import com.clockbyte.admobadapter.AdmobFetcherBase; import com.clockbyte.admobadapter.R; +import com.google.android.gms.ads.AdSize; import com.google.android.gms.ads.NativeExpressAdView; /** * Adapter that has common functionality for any adapters that need to show ads in-between * other data. */ -public class AdmobExpressAdapterWrapper extends BaseAdapter implements AdmobFetcherBase.AdmobListener { +public class AdmobExpressAdapterWrapper extends BaseAdapter implements AdmobFetcherBase.AdmobListener, + AdmobAdapterWrapperInterface { private final String TAG = AdmobExpressAdapterWrapper.class.getCanonicalName(); @@ -59,14 +65,24 @@ public void onInvalidated() { AdmobFetcherExpress adFetcher; Context mContext; + private AdmobAdapterCalculator AdapterCalculator = new AdmobAdapterCalculator(this); + /* + * Gets an object which incapsulates transformation of the source and ad blocks indices + */ + public AdmobAdapterCalculator getAdapterCalculator(){return AdapterCalculator;} + /* +* Injects an object which incapsulates transformation of the source and ad blocks indices. You could override calculations +* by inheritance of AdmobAdapterCalculator class +*/ + public void setAdapterCalculator(AdmobAdapterCalculator adapterCalculatordmob){AdapterCalculator = adapterCalculatordmob;} private static final int VIEW_TYPE_COUNT = 1; private static final int VIEW_TYPE_AD_EXPRESS = 1; private final static int DEFAULT_NO_OF_DATA_BETWEEN_ADS = 10; private final static int DEFAULT_LIMIT_OF_ADS = 3; - - private int mNoOfDataBetweenAds; + private static final AdSize DEFAULT_AD_SIZE = new AdSize(AdSize.FULL_WIDTH, 150); + private static final String DEFAULT_AD_UNIT_ID = "ca-app-pub-3940256099942544/1072772517"; /* * Gets the number of your data items between ad blocks, by default it equals to 10. @@ -75,9 +91,8 @@ public void onInvalidated() { * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices */ public int getNoOfDataBetweenAds() { - return mNoOfDataBetweenAds; + return AdapterCalculator.getNoOfDataBetweenAds(); } - /* * Sets the number of your data items between ad blocks, by default it equals to 10. * You should set it according to the Admob's policies and rules which says not to @@ -85,52 +100,85 @@ public int getNoOfDataBetweenAds() { * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices */ public void setNoOfDataBetweenAds(int mNoOfDataBetweenAds) { - this.mNoOfDataBetweenAds = mNoOfDataBetweenAds; + AdapterCalculator.setNoOfDataBetweenAds(mNoOfDataBetweenAds); } - private int mLimitOfAds; + public int getFirstAdIndex() { + return AdapterCalculator.getFirstAdIndex(); + } + /* + * Sets the first ad block index (zero-based) in the adapter, by default it equals to 0 + */ + public void setFirstAdIndex(int firstAdIndex) { + AdapterCalculator.setFirstAdIndex(firstAdIndex); + } /* * Gets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) */ public int getLimitOfAds() { - return mLimitOfAds; + return AdapterCalculator.getLimitOfAds(); } /* * Sets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) */ public void setLimitOfAds(int mLimitOfAds) { - this.mLimitOfAds = mLimitOfAds; + AdapterCalculator.setLimitOfAds(mLimitOfAds); } - private int mExpressAdsLayoutId; + private String mAdsUnitId; /* * Gets the res layout id for published express ads */ - public int getExpressAdsLayoutId() { - return mExpressAdsLayoutId; + public String getAdsUnitId() { + return mAdsUnitId; } /* * Sets the res layout id for published express ads */ - public void setExpressAdsLayoutId(int mExpressAdsLayoutId) { - this.mExpressAdsLayoutId = mExpressAdsLayoutId; + public void setAdsUnitId(String mAdsUnitId) { + this.mAdsUnitId = mAdsUnitId; + } + + /* + *Add a test device ID. + */ + public void addTestDeviceId(String testDeviceId) { + adFetcher.addTestDeviceId(testDeviceId); } /* *Sets a test device ID. Normally you don't have to set it */ + @Deprecated public void setTestDeviceId(String testDeviceId) { - adFetcher.setTestDeviceId(testDeviceId); + adFetcher.addTestDeviceId(testDeviceId); + } + + private AdSize mAdSize; + + /* + * Gets ad size + */ + public AdSize getAdSize() { + return mAdSize; + } + + /* + * Sets ad size + */ + public void setAdSize(AdSize mAdSize) { + this.mAdSize = mAdSize; } public AdmobExpressAdapterWrapper(Context context) { setNoOfDataBetweenAds(DEFAULT_NO_OF_DATA_BETWEEN_ADS); setLimitOfAds(DEFAULT_LIMIT_OF_ADS); - setExpressAdsLayoutId(R.layout.adexpresslistview_item); + setAdsUnitId(DEFAULT_AD_UNIT_ID); + setAdSize(DEFAULT_AD_SIZE); mContext = context; adFetcher = new AdmobFetcherExpress(mContext); @@ -152,17 +200,17 @@ public View getView(int position, View convertView, ViewGroup parent) { } return item; default: - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getView(origPos, convertView, parent); } } private NativeExpressAdView getExpressAdView(ViewGroup parent) { - // Inflate a layout and add it to the parent ViewGroup. - LayoutInflater inflater = (LayoutInflater) parent.getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - NativeExpressAdView adView = (NativeExpressAdView) inflater - .inflate(getExpressAdsLayoutId(), parent, false); + NativeExpressAdView adView = new NativeExpressAdView(mContext); + adView.setAdSize(getAdSize()); + adView.setAdUnitId(getAdsUnitId()); + adView.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, + AbsListView.LayoutParams.WRAP_CONTENT)); return adView; } @@ -184,19 +232,13 @@ public int getCount() { No of currently fetched ads, as long as it isn't more than no of max ads that can fit dataset. */ - int noOfAds = getAdsCountToPublish(); + int noOfAds = AdapterCalculator.getAdsCountToPublish(); return mAdapter.getCount() > 0 ? mAdapter.getCount() + noOfAds : 0; } else { return 0; } } - public int getAdsCountToPublish(){ - int noOfAds = Math.min(adFetcher.getFetchedAdsCount(), - mAdapter.getCount() / getNoOfDataBetweenAds()); - return Math.min(noOfAds, getLimitOfAds()); - } - /** * Gets the item in a given position in the dataset. If an ad is to be returned, * a {@link NativeExpressAdView} object is returned. @@ -207,11 +249,11 @@ public int getAdsCountToPublish(){ @Override public Object getItem(int position) { - if (canShowAdAtPosition(position)) { - int adPos = getAdIndex(position); + if (AdapterCalculator.canShowAdAtPosition(position)) { + int adPos = AdapterCalculator.getAdIndex(position); return adFetcher.getAdForIndex(adPos); } else { - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getItem(origPos); } } @@ -228,75 +270,14 @@ public int getViewTypeCount() { @Override public int getItemViewType(int position) { - if (canShowAdAtPosition(position)) { + if (AdapterCalculator.canShowAdAtPosition(position)) { return VIEW_TYPE_AD_EXPRESS; } else { - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getItemViewType(origPos); } } - /** - * Translates an adapter position to an actual position within the underlying dataset. - * - * @param position the adapter position - * @return the original position that the adapter position would have been without ads - */ - protected int getOriginalContentPosition(int position) { - int noOfAds = getAdsCountToPublish(); - // No of spaces for ads in the dataset, according to ad placement rules - int adSpacesCount = position / (getNoOfDataBetweenAds() + 1); - return position - Math.min(adSpacesCount, noOfAds); - } - - /** - * Determines if an ad can be shown at the given position. Checks if the position is for - * an ad, using the preconfigured ad positioning rules; and if a native ad object is - * available to place in that position. - * - * @param position the adapter position - * @return true if ads can - */ - protected boolean canShowAdAtPosition(int position) { - - // Is this a valid position for an ad? - // Is an ad for this position available? - return isAdPosition(position) && isAdAvailable(position); - } - - /** - * Gets the ad index for this adapter position within the list of currently fetched ads. - * - * @param position the adapter position - * @return the index of the ad within the list of fetched ads - */ - private int getAdIndex(int position) { - return (position / getNoOfDataBetweenAds()) - 1; - } - - /** - * Checks if adapter position is an ad position. - * - * @param position the adapter position - * @return {@code true} if an ad position, {@code false} otherwise - */ - private boolean isAdPosition(int position) { - return (position + 1) % (getNoOfDataBetweenAds() + 1) == 0; - } - - /** - * Checks if an ad is available for this position. - * - * @param position the adapter position - * @return {@code true} if an ad is available, {@code false} otherwise - */ - private boolean isAdAvailable(int position) { - int adIndex = getAdIndex(position); - return position >= getNoOfDataBetweenAds() - && adIndex >= 0 - && adIndex < getLimitOfAds(); - } - /** * Destroys all currently fetched ads */ @@ -316,4 +297,9 @@ public void onAdCountChanged() { notifyDataSetChanged(); } + + @Override + public int getAdapterCount() { + return mAdapter.getCount(); + } } diff --git a/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobExpressRecyclerAdapterWrapper.java b/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobExpressRecyclerAdapterWrapper.java index 6d7ae71..7111543 100644 --- a/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobExpressRecyclerAdapterWrapper.java +++ b/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobExpressRecyclerAdapterWrapper.java @@ -19,34 +19,34 @@ import android.content.Context; import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; +import com.clockbyte.admobadapter.AdmobAdapterCalculator; +import com.clockbyte.admobadapter.AdmobAdapterWrapperInterface; import com.clockbyte.admobadapter.AdmobFetcherBase; import com.clockbyte.admobadapter.R; import com.clockbyte.admobadapter.RecyclerViewAdapterBase; import com.clockbyte.admobadapter.ViewWrapper; +import com.google.android.gms.ads.AdSize; import com.google.android.gms.ads.NativeExpressAdView; /** * Adapter that has common functionality for any adapters that need to show ads in-between * other data. */ -public class AdmobExpressRecyclerAdapterWrapper - extends RecyclerView.Adapter> - implements AdmobFetcherBase.AdmobListener { +public class AdmobExpressRecyclerAdapterWrapper extends RecyclerView.Adapter> + implements AdmobFetcherBase.AdmobListener, AdmobAdapterWrapperInterface { private final String TAG = AdmobExpressRecyclerAdapterWrapper.class.getCanonicalName(); - private RecyclerViewAdapterBase mAdapter; + private RecyclerViewAdapterBase mAdapter; - public RecyclerViewAdapterBase getAdapter() { + public RecyclerViewAdapterBase getAdapter() { return mAdapter; } - public void setAdapter(RecyclerViewAdapterBase adapter) { + public void setAdapter(RecyclerViewAdapterBase adapter) { mAdapter = adapter; mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { @Override @@ -59,13 +59,24 @@ public void onChanged() { AdmobFetcherExpress adFetcher; Context mContext; + private AdmobAdapterCalculator AdapterCalculator = new AdmobAdapterCalculator(this); + /* + * Gets an object which incapsulates transformation of the source and ad blocks indices + */ + public AdmobAdapterCalculator getAdapterCalculator(){return AdapterCalculator;} + /* +* Injects an object which incapsulates transformation of the source and ad blocks indices. You could override calculations +* by inheritance of AdmobAdapterCalculator class +*/ + public void setAdapterCalculator(AdmobAdapterCalculator adapterCalculatordmob){AdapterCalculator = adapterCalculatordmob;} + private static final int VIEW_TYPE_AD_EXPRESS = 1; private final static int DEFAULT_NO_OF_DATA_BETWEEN_ADS = 10; private final static int DEFAULT_LIMIT_OF_ADS = 3; - - private int mNoOfDataBetweenAds; + private static final AdSize DEFAULT_AD_SIZE = new AdSize(AdSize.FULL_WIDTH, 150); + private static final String DEFAULT_AD_UNIT_ID = "ca-app-pub-3940256099942544/1072772517"; /* * Gets the number of your data items between ad blocks, by default it equals to 10. @@ -74,7 +85,7 @@ public void onChanged() { * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices */ public int getNoOfDataBetweenAds() { - return mNoOfDataBetweenAds; + return AdapterCalculator.getNoOfDataBetweenAds(); } /* @@ -84,52 +95,86 @@ public int getNoOfDataBetweenAds() { * so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices */ public void setNoOfDataBetweenAds(int mNoOfDataBetweenAds) { - this.mNoOfDataBetweenAds = mNoOfDataBetweenAds; + AdapterCalculator.setNoOfDataBetweenAds(mNoOfDataBetweenAds); + } + + public int getFirstAdIndex() { + return AdapterCalculator.getFirstAdIndex(); } - private int mLimitOfAds; + /* + * Sets the first ad block index (zero-based) in the adapter, by default it equals to 0 + */ + public void setFirstAdIndex(int firstAdIndex) { + AdapterCalculator.setFirstAdIndex(firstAdIndex); + } /* * Gets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) */ public int getLimitOfAds() { - return mLimitOfAds; + return AdapterCalculator.getLimitOfAds(); } /* * Sets the max count of ad blocks per dataset, by default it equals to 3 (according to the Admob's policies and rules) */ public void setLimitOfAds(int mLimitOfAds) { - this.mLimitOfAds = mLimitOfAds; + AdapterCalculator.setLimitOfAds(mLimitOfAds); } - private int mExpressAdsLayoutId; + private String mAdsUnitId; /* * Gets the res layout id for published express ads */ - public int getExpressAdsLayoutId() { - return mExpressAdsLayoutId; + public String getAdsUnitId() { + return mAdsUnitId; } /* * Sets the res layout id for published express ads */ - public void setExpressAdsLayoutId(int mExpressAdsLayoutId) { - this.mExpressAdsLayoutId = mExpressAdsLayoutId; + public void setAdsUnitId(String mAdsUnitId) { + this.mAdsUnitId = mAdsUnitId; + } + + /* + *Add a test device ID. + */ + public void addTestDeviceId(String testDeviceId) { + adFetcher.addTestDeviceId(testDeviceId); } /* *Sets a test device ID. Normally you don't have to set it */ + @Deprecated public void setTestDeviceId(String testDeviceId) { - adFetcher.setTestDeviceId(testDeviceId); + adFetcher.addTestDeviceId(testDeviceId); + } + + private AdSize mAdSize; + + /* + * Gets ad size + */ + public AdSize getAdSize() { + return mAdSize; + } + + /* + * Sets ad size + */ + public void setAdSize(AdSize mAdSize) { + this.mAdSize = mAdSize; } public AdmobExpressRecyclerAdapterWrapper(Context context) { setNoOfDataBetweenAds(DEFAULT_NO_OF_DATA_BETWEEN_ADS); setLimitOfAds(DEFAULT_LIMIT_OF_ADS); - setExpressAdsLayoutId(R.layout.adexpresslistview_item); + setAdsUnitId(DEFAULT_AD_UNIT_ID); + setAdSize(DEFAULT_AD_SIZE); mContext = context; adFetcher = new AdmobFetcherExpress(mContext); @@ -138,11 +183,11 @@ public AdmobExpressRecyclerAdapterWrapper(Context context) { @Override public void onBindViewHolder(ViewWrapper viewHolder, int position) { - if (viewHolder==null) + if (viewHolder == null) return; - if(viewHolder.getItemViewType()!=VIEW_TYPE_AD_EXPRESS){ - int origPos = getOriginalContentPosition(position); + if (viewHolder.getItemViewType() != VIEW_TYPE_AD_EXPRESS) { + int origPos = AdapterCalculator.getOriginalContentPosition(position); mAdapter.onBindViewHolder(viewHolder, origPos); } } @@ -154,18 +199,18 @@ public final ViewWrapper onCreateViewHolder(ViewGroup parent, int viewType) { NativeExpressAdView item = getExpressAdView(parent); adFetcher.setupAd(item); adFetcher.fetchAd(item); - return new ViewWrapper((V)item); + return new ViewWrapper((V) item); default: return mAdapter.onCreateViewHolder(parent, viewType); } } private NativeExpressAdView getExpressAdView(ViewGroup parent) { - // Inflate a layout and add it to the parent ViewGroup. - LayoutInflater inflater = (LayoutInflater) parent.getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - NativeExpressAdView adView = (NativeExpressAdView) inflater - .inflate(getExpressAdsLayoutId(), parent, false); + NativeExpressAdView adView = new NativeExpressAdView(mContext); + adView.setAdSize(getAdSize()); + adView.setAdUnitId(getAdsUnitId()); + adView.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, + RecyclerView.LayoutParams.WRAP_CONTENT)); return adView; } @@ -187,19 +232,13 @@ public int getItemCount() { No of currently fetched ads, as long as it isn't more than no of max ads that can fit dataset. */ - int noOfAds = getAdsCountToPublish(); + int noOfAds = AdapterCalculator.getAdsCountToPublish(); return mAdapter.getItemCount() > 0 ? mAdapter.getItemCount() + noOfAds : 0; } else { return 0; } } - public int getAdsCountToPublish(){ - int noOfAds = Math.min(adFetcher.getFetchedAdsCount(), - mAdapter.getItemCount() / getNoOfDataBetweenAds()); - return Math.min(noOfAds, getLimitOfAds()); - } - @Override public long getItemId(int position) { return position; @@ -207,75 +246,14 @@ public long getItemId(int position) { @Override public int getItemViewType(int position) { - if (canShowAdAtPosition(position)) { + if (AdapterCalculator.canShowAdAtPosition(position)) { return VIEW_TYPE_AD_EXPRESS; } else { - int origPos = getOriginalContentPosition(position); + int origPos = AdapterCalculator.getOriginalContentPosition(position); return mAdapter.getItemViewType(origPos); } } - /** - * Translates an adapter position to an actual position within the underlying dataset. - * - * @param position the adapter position - * @return the original position that the adapter position would have been without ads - */ - protected int getOriginalContentPosition(int position) { - int noOfAds = getAdsCountToPublish(); - // No of spaces for ads in the dataset, according to ad placement rules - int adSpacesCount = position / (getNoOfDataBetweenAds() + 1); - return position - Math.min(adSpacesCount, noOfAds); - } - - /** - * Determines if an ad can be shown at the given position. Checks if the position is for - * an ad, using the preconfigured ad positioning rules; and if a native ad object is - * available to place in that position. - * - * @param position the adapter position - * @return true if ads can - */ - protected boolean canShowAdAtPosition(int position) { - - // Is this a valid position for an ad? - // Is an ad for this position available? - return isAdPosition(position) && isAdAvailable(position); - } - - /** - * Gets the ad index for this adapter position within the list of currently fetched ads. - * - * @param position the adapter position - * @return the index of the ad within the list of fetched ads - */ - private int getAdIndex(int position) { - return (position / getNoOfDataBetweenAds()) - 1; - } - - /** - * Checks if adapter position is an ad position. - * - * @param position the adapter position - * @return {@code true} if an ad position, {@code false} otherwise - */ - private boolean isAdPosition(int position) { - return (position + 1) % (getNoOfDataBetweenAds() + 1) == 0; - } - - /** - * Checks if an ad is available for this position. - * - * @param position the adapter position - * @return {@code true} if an ad is available, {@code false} otherwise - */ - private boolean isAdAvailable(int position) { - int adIndex = getAdIndex(position); - return position >= getNoOfDataBetweenAds() - && adIndex >= 0 - && adIndex < getLimitOfAds(); - } - /** * Destroys all currently fetched ads */ @@ -295,4 +273,9 @@ public void onAdCountChanged() { notifyDataSetChanged(); } + + @Override + public int getAdapterCount() { + return mAdapter.getItemCount(); + } } diff --git a/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobFetcherExpress.java b/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobFetcherExpress.java index f2c1f36..8584528 100644 --- a/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobFetcherExpress.java +++ b/admobadapter/src/main/java/com/clockbyte/admobadapter/expressads/AdmobFetcherExpress.java @@ -19,14 +19,10 @@ import android.content.Context; import android.os.Handler; -import android.text.TextUtils; import android.util.Log; -import android.view.View; import com.clockbyte.admobadapter.AdmobFetcherBase; -import com.clockbyte.admobadapter.R; import com.google.android.gms.ads.AdListener; -import com.google.android.gms.ads.AdSize; import com.google.android.gms.ads.NativeExpressAdView; import java.lang.ref.WeakReference; diff --git a/admobadapter/src/main/res/layout/adexpresslistview_item.xml b/admobadapter/src/main/res/layout/adexpresslistview_item.xml deleted file mode 100644 index a16ffaa..0000000 --- a/admobadapter/src/main/res/layout/adexpresslistview_item.xml +++ /dev/null @@ -1,10 +0,0 @@ - - \ No newline at end of file diff --git a/sampleapp/sampleapp.iml b/sampleapp/sampleapp.iml index 7ee2ad7..7b3ac4d 100644 --- a/sampleapp/sampleapp.iml +++ b/sampleapp/sampleapp.iml @@ -64,14 +64,6 @@ - - - - - - - - @@ -80,6 +72,14 @@ + + + + + + + + diff --git a/sampleapp/src/main/AndroidManifest.xml b/sampleapp/src/main/AndroidManifest.xml index c2f8e0b..cbc38bf 100644 --- a/sampleapp/src/main/AndroidManifest.xml +++ b/sampleapp/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ android:label="@string/app_name" android:theme="@style/AppTheme" > diff --git a/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/MainActivity_ListView.java b/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/MainActivity_ListView.java index f44c06c..7f0c35a 100644 --- a/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/MainActivity_ListView.java +++ b/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/MainActivity_ListView.java @@ -5,6 +5,7 @@ import android.widget.ArrayAdapter; import android.widget.ListView; import com.clockbyte.admobadapter.AdmobAdapterWrapper; +import com.google.android.gms.ads.MobileAds; import java.util.ArrayList; import java.util.Timer; @@ -21,6 +22,10 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_listview); + //highly-recommended in Firebase docs to initialize things early as possible + //test_admob_app_id is different with unit_id! you could get it in your Admob console + MobileAds.initialize(getApplicationContext(), getString(R.string.test_admob_app_id)); + initListViewItems(); initUpdateAdsTimer(); } @@ -51,6 +56,8 @@ private void initListViewItems() { // so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices adapterWrapper.setNoOfDataBetweenAds(10); + adapterWrapper.setFirstAdIndex(2); + //It's a test admob ID. Please replace it with a real one only when you will be ready to deploy your product to the Release! //Otherwise your Admob account could be banned //String admobUnitId = getResources().getString(R.string.banner_admob_unit_id); diff --git a/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/MainActivity_RecyclerView.java b/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/MainActivity_RecyclerView.java index 1421ea3..ce180d1 100644 --- a/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/MainActivity_RecyclerView.java +++ b/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/MainActivity_RecyclerView.java @@ -7,6 +7,7 @@ import android.widget.ArrayAdapter; import com.clockbyte.admobadapter.AdmobRecyclerAdapterWrapper; +import com.google.android.gms.ads.MobileAds; import java.util.ArrayList; import java.util.Timer; @@ -23,6 +24,10 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_recycleview); + //highly-recommended in Firebase docs to initialize things early as possible + //test_admob_app_id is different with unit_id! you could get it in your Admob console + MobileAds.initialize(getApplicationContext(), getString(R.string.test_admob_app_id)); + initRecyclerViewItems(); initUpdateAdsTimer(); } @@ -53,6 +58,8 @@ private void initRecyclerViewItems() { // so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices adapterWrapper.setNoOfDataBetweenAds(10); + adapterWrapper.setFirstAdIndex(2); + //It's a test admob ID. Please replace it with a real one only when you will be ready to deploy your product to the Release! //Otherwise your Admob account could be banned //String admobUnitId = getResources().getString(R.string.banner_admob_unit_id); diff --git a/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/express/MainActivity_ListView_Express.java b/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/express/MainActivity_ListView_Express.java index 98e297b..7c113bf 100644 --- a/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/express/MainActivity_ListView_Express.java +++ b/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/express/MainActivity_ListView_Express.java @@ -7,6 +7,9 @@ import com.clockbyte.admobadapter.expressads.AdmobExpressAdapterWrapper; import com.clockbyte.admobadapter.sampleapp.R; +import com.google.android.gms.ads.AdRequest; +import com.google.android.gms.ads.AdSize; +import com.google.android.gms.ads.MobileAds; import java.util.ArrayList; import java.util.Timer; @@ -23,6 +26,10 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_listview); + //highly-recommended in Firebase docs to initialize things early as possible + //test_admob_app_id is different with unit_id! you could get it in your Admob console + MobileAds.initialize(getApplicationContext(), getString(R.string.test_admob_app_id)); + initListViewItems(); initUpdateAdsTimer(); } @@ -42,7 +49,8 @@ private void initListViewItems() { //TODO it's important to set your test device ID (you can find it in LogCat after launching the debug session i.e. by word "test") //if you launch app on emulator and experience some troubles // try passing the constant AdRequest.DEVICE_ID_EMULATOR - adapterWrapper.setTestDeviceId(getString(R.string.testDeviceID));//set an unique test device ID + adapterWrapper.addTestDeviceId(getString(R.string.testDeviceID));//set an unique test device ID + adapterWrapper.addTestDeviceId(AdRequest.DEVICE_ID_EMULATOR); //TODO set the custom ads layout if you wish. NOTE you have to set your admob unit ID in this XML. //It doesn't work for me if I set the unit ID in code with the method setAdUnitID() so it seems to be a bug //adapterWrapper.setExpressAdsLayoutId(R.layout.adexpresslistview_item); @@ -57,10 +65,11 @@ private void initListViewItems() { // so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices adapterWrapper.setNoOfDataBetweenAds(10); - //It's a test admob ID. Please replace it with a real one only when you will be ready to deploy your product to the Release! - //Otherwise your Admob account could be banned - //String admobUnitId = getResources().getString(R.string.banner_admob_unit_id); - //adapterWrapper.setAdmobReleaseUnitId(admobUnitId); + adapterWrapper.setFirstAdIndex(2); + //due to the docs you should set the ad size before ads will be loaded + //AdSize.FULL_WIDTH x 150 is default size. + adapterWrapper.setAdSize(new AdSize(AdSize.FULL_WIDTH,150)); + adapterWrapper.setAdsUnitId(getString(R.string.test_admob_express_unit_id)); lvMessages.setAdapter(adapterWrapper); // setting an AdmobAdapterWrapper to a ListView diff --git a/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/express/MainActivity_RecyclerView_Express.java b/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/express/MainActivity_RecyclerView_Express.java index 9150ef8..6c39e9f 100644 --- a/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/express/MainActivity_RecyclerView_Express.java +++ b/sampleapp/src/main/java/com/clockbyte/admobadapter/sampleapp/express/MainActivity_RecyclerView_Express.java @@ -8,6 +8,9 @@ import com.clockbyte.admobadapter.expressads.AdmobExpressRecyclerAdapterWrapper; import com.clockbyte.admobadapter.sampleapp.R; import com.clockbyte.admobadapter.sampleapp.RecyclerExampleAdapter; +import com.google.android.gms.ads.AdRequest; +import com.google.android.gms.ads.AdSize; +import com.google.android.gms.ads.MobileAds; import java.util.ArrayList; import java.util.Timer; @@ -24,6 +27,10 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_recycleview); + //highly-recommended in Firebase docs to initialize things early as possible + //test_admob_app_id is different with unit_id! you could get it in your Admob console + MobileAds.initialize(getApplicationContext(), getString(R.string.test_admob_app_id)); + initRecyclerViewItems(); initUpdateAdsTimer(); } @@ -43,7 +50,8 @@ private void initRecyclerViewItems() { //TODO it's important to set your test device ID (you can find it in LogCat after launching the debug session i.e. by word "test") //if you launch app on emulator and experience some troubles // try passing the constant AdRequest.DEVICE_ID_EMULATOR - adapterWrapper.setTestDeviceId(getString(R.string.testDeviceID));//set an unique test device ID + adapterWrapper.addTestDeviceId(getString(R.string.testDeviceID));//set an unique test device ID + adapterWrapper.addTestDeviceId(AdRequest.DEVICE_ID_EMULATOR); //TODO set the custom ads layout if you wish. NOTE you have to set your admob unit ID in this XML. //It doesn't work for me if I set the unit ID in code with the method setAdUnitID() so it seems to be a bug //adapterWrapper.setExpressAdsLayoutId(R.layout.adexpresslistview_item); @@ -58,10 +66,11 @@ private void initRecyclerViewItems() { // so you should choose this parameter carefully and according to your item's height and screen resolution of a target devices adapterWrapper.setNoOfDataBetweenAds(10); - //It's a test admob ID. Please replace it with a real one only when you will be ready to deploy your product to the Release! - //Otherwise your Admob account could be banned - //String admobUnitId = getResources().getString(R.string.banner_admob_unit_id); - //adapterWrapper.setAdmobReleaseUnitId(admobUnitId); + adapterWrapper.setFirstAdIndex(2); + //due to the docs you should set the ad size before ads will be loaded + //AdSize.FULL_WIDTH x 150 is default size. + adapterWrapper.setAdSize(new AdSize(AdSize.FULL_WIDTH,150)); + adapterWrapper.setAdsUnitId(getString(R.string.test_admob_express_unit_id)); rvMessages.setAdapter(adapterWrapper); // setting an AdmobExpressRecyclerAdapterWrapper to a RecyclerView diff --git a/sampleapp/src/main/res/values/strings.xml b/sampleapp/src/main/res/values/strings.xml index 7ed638e..9d16040 100644 --- a/sampleapp/src/main/res/values/strings.xml +++ b/sampleapp/src/main/res/values/strings.xml @@ -2,4 +2,6 @@ admobadapter-sampleapp ca-app-pub-xxx/xxx 6BA3752AF66F8D8553248A71886E648D + ca-app-pub-3940256099942544~3347511713 + ca-app-pub-3940256099942544/1072772517