My app displays banner ads and interstitial ads. The ads are displayed correctly on API levels 32, 33 and 34 (API level 31 not tested). But on API levels 29 and 30, the ads are wrong scaled, so they don’t fit on the display (see screenshots). This is the same for AVD and for physical devices.
Can anyone help with this problem? Has anyone the same problem?
Code follows below.
relevant imports:
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.FullScreenContentCallback;
import com.google.android.gms.ads.LoadAdError;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.admanager.AdManagerAdRequest;
import com.google.android.gms.ads.admanager.AdManagerAdView;
import com.google.android.gms.ads.admanager.AdManagerInterstitialAd;
import com.google.android.gms.ads.admanager.AdManagerInterstitialAdLoadCallback;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.initialization.AdapterStatus;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
AdMob initialization, called from main activity’s onCreate:
public void initAdMob() {
if ( adMobinitialized ) return;
OnInitializationCompleteListener listener =
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus status) {
adMobinitialized = true;
setupBannerAd();
loadBannerAd();
setupInterstitialAd();
}
};
MobileAds.initialize ( parentAct, listener );
}
other methods called from the main activity’s corresponding methods:
public void onResume() {
if ( bannerAdView != null ) bannerAdView.resume();
}
public void onPause() {
if ( bannerAdView != null ) bannerAdView.pause();
}
public void onDestroy() {
if ( bannerAdView != null ) {
bannerAdView.destroy();
bannerAdView = null;
}
}
code for banner ad:
public void setupBannerAd () {
if (!adMobinitialized) return;
if ( bannerAdContainer == null ) {
ViewGroup container = parentAct.findViewById (R.id.bannerAdContainer);
if (container == null) {
return; // container not found
}
bannerAdContainer = container;
}
//
// The ad size can only be set once on AdView. Therefore,
// if the requested size changes, we have to create a new AdView object.
// This is done by checkAdViewSize.
//
AdSize as = getAdContainerSize();
checkAdViewSize ( as );
if ( bannerAdView == null ) {
bannerAdView = new AdManagerAdView(parentAct);
bannerAdView.setAdUnitId(useTestAds ?
BannerAdUnitIDTEST : BannerAdUnitIDPROD);
setupAdMobListener(bannerAdView);
bannerAdView.setScaleX(1f); // no scaling
bannerAdView.setScaleY(1f);
bannerAdView.setAdSize(as);
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.MATCH_CONSTRAINT);
lp.startToStart = ConstraintLayout.LayoutParams.PARENT_ID;
lp.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID;
// lp.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
lp.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID;
bannerAdView.setLayoutParams(lp);
// bannerAdView.setBackgroundColor(R.attr.testFuncBtn);
bannerAdContainer.addView(bannerAdView);
}
}
/**
* if ad size requirement changes, we have to create a new AdView object
*
* @param requestedSize requested ad size
*/
private void checkAdViewSize ( AdSize requestedSize ) {
if ( bannerAdView == null ) return;
AdSize currentSize = bannerAdView.getAdSize();
if ( requestedSize.getWidth() != currentSize.getWidth() ||
requestedSize.getHeight() != currentSize.getHeight() )
bannerAdView = null; // force new object
}
/**
* calculate container size for banner ad
* currently hardcoded approach by using predefiend dimensions and display width
*
* @return AdSize object
*/
private AdSize getAdContainerSize() {
Configuration cfg = parentAct.getResources().getConfiguration();
Resources r = parentAct.getResources();
Rect displayBoundsDip = myUtil.getWindowRectDip(parentAct);
// float displayDensityAlways1 = myUtil.getDisplayDens(parentAct);
//
// width share of banner view (landscape):
int widthShare = (int) getFloatValue ( r, R.dimen.bavWidthShareLandscape );
int heightPort = getDpDimension( r, R.dimen.bavHeightPortrait );
int heightLand = getDpDimension( r, R.dimen.bavHeightLandscape );
int adWidthDip, adHeightDip;
if ( displayBoundsDip != null ) {
if ( myUtil.OrientationIsPortrait(cfg) ) {
adWidthDip = (int) displayBoundsDip.width() - 16; // subtract margins
}
else {
float adHorSpaceDip = displayBoundsDip.width() * widthShare / 100f;
adWidthDip = (int) adHorSpaceDip - 8; // subtract margins
}
}
else
adWidthDip = 0;
adHeightDip = myutil.OrientationIsPortrait(cfg) ? heightPort : heightLand;
AdSize as = new AdSize ( adWidthDip, adHeightDip );
// AdSize as = AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(parentAct, adWidthDip);
String adstr = as.toString();
return as;
}
private float getFloatValue ( Resources r, int id ) {
TypedValue tv = new TypedValue();
r.getValue ( id, tv, false );
if ( tv.type == TypedValue.TYPE_FLOAT )
return tv.getFloat();
else
return 0f;
}
private int getDpDimension ( Resources r, int id ) {
TypedValue tv = new TypedValue();
r.getValue ( id, tv, false );
if ( tv.type == TypedValue.TYPE_DIMENSION ) {
CharSequence c = tv.coerceToString();
StringBuilder s = new StringBuilder(c);
// string is e.g. "60.0dip"
// remove "dp":
int l = s.length();
if ( s.toString().contains("dip") )
s.delete(l-3,l);
else if ( s.toString().contains("dp") )
s.delete(l-2,l);
return (int) Float.parseFloat ( s.toString() );
}
else
return 0;
}
public void loadBannerAd() {
if (!adMobinitialized) return;
if (bannerAdContainer == null || bannerAdView == null) return;
// Start loading the ad in the background.
AdManagerAdRequest.Builder b = new AdManagerAdRequest.Builder();
AdManagerAdRequest adRequest = b.build();
bannerAdView.loadAd(adRequest);
}
private void setupAdMobListener(AdManagerAdView adview) {
adview.setAdListener(new AdListener() {
@Override
public void onAdFailedToLoad(LoadAdError e) {
super.onAdFailedToLoad(e);
}
@Override
public void onAdClosed() {
super.onAdClosed();
}
// @Override
// public void onAdLeftApplication() {
// super.onAdLeftApplication();
// }
//
@Override
public void onAdOpened() {
super.onAdOpened();
}
@Override
public void onAdLoaded() {
super.onAdLoaded();
}
@Override
public void onAdClicked() {
super.onAdClicked();
}
@Override
public void onAdImpression() {
super.onAdImpression();
}
});
}
code for interstitial ad:
private void setupInterstitialAd() {
if (!adMobinitialized) return;
interstitialAd = null;
String adUnitID = useTestAds ? InterstitialAdUnitIDTEST : InterstitialAdUnitIDPROD;
AdManagerAdRequest adRequest = new AdManagerAdRequest.Builder().build();
AdManagerInterstitialAdLoadCallback callb = new AdManagerInterstitialAdLoadCallback() {
@Override
public void onAdLoaded(@NonNull AdManagerInterstitialAd ad) {
// The interstitialAd reference will be null until an ad is loaded.
interstitialAd = ad;
setFullScreenCallback () ;
}
@Override
public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
interstitialAd = null;
}
};
AdManagerInterstitialAd.load ( parentAct, adUnitID, adRequest, callb);
}
private void setFullScreenCallback ( ) {
if ( interstitialAd == null ) return;
interstitialAd.setFullScreenContentCallback ( new FullScreenContentCallback() {
@Override
public void onAdClicked() {
// Called when a click is recorded for an ad.
}
@Override
public void onAdDismissedFullScreenContent() {
// Called when ad is dismissed.
// Set the ad reference to null so you don't show the ad a second time.
interstitialAd = null;
}
@Override
public void onAdFailedToShowFullScreenContent(AdError adError) {
// Called when ad fails to show.
interstitialAd = null;
}
@Override
public void onAdImpression() {
// Called when an impression is recorded for an ad.
}
@Override
public void onAdShowedFullScreenContent() {
// Called when ad is shown.
}
});
}
/**
* display interstitial ad
*/
public void showInterstitialAd() {
if (interstitialAd != null) {
Rect r = myUtil.getWindowRectDip(parentAct); // this displays screen size
Activity a = parentAct;
interstitialAd.show(a);
} else {
setupInterstitialAd(); // load a new one
}
}
And finally code in the main activity’s onResume. I also tried to call the methods directly (without postDelayed), but this had no effect:
rootView.postDelayed ( new Runnable() {
@Override public void run() {
setupBannerAd ();
loadBannerAd();
showInterStitialAd(false);
}
}, 500 );