ratson / cordova-plugin-admob-free

New development has been moved to "admob-plus-cordova", https://github.com/admob-plus/admob-plus/tree/master/packages/cordova
https://github.com/admob-plus/admob-plus
MIT License
499 stars 214 forks source link

UI bounces on refreshing #339

Closed ivanov84 closed 5 years ago

ivanov84 commented 5 years ago

Users claim that when ad refresh ui bounces. Is there a way to freeze ui so that when the advertisement is updated on the banner, the interface is not twitching?

srikanth-wgl commented 5 years ago

Using overlap: true will solve this issue. But banner will overlap app content. You need to take care of it yourself in the app (probably by adding some padding at the bottom/top).

ivanov84 commented 5 years ago

@srikanth-wgl Thank you. I will try to do it.

ivanov84 commented 3 years ago

I would like to share with my new fix: (I created wrapper layout in android code - BannerExecutor.java)

package name.ratson.cordova.admob.banner;

import android.util.Log;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.Gravity;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.AdSize;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONObject;

import name.ratson.cordova.admob.AbstractExecutor;
import name.ratson.cordova.admob.AdMob;

public class BannerExecutor extends AbstractExecutor {
    private static final String TAG = "BannerExecutor";

    /**
     * The adView to display to the user.
     */
    private AdView adView;
    /**
     * if want banner view overlap webview, we will need this layout
     */
    private RelativeLayout adViewLayout = null;

    private ViewGroup parentView;
    private ViewGroup wrapperView;

    private boolean bannerShow = true;
    private boolean ivanovIsParentViewModified = false;

    boolean bannerVisible = false;

    public BannerExecutor(AdMob plugin) {
        super(plugin);
    }

    @Override
    public String getAdType() {
        return "banner";
    }

    /**
     * Parses the createAd banner view input parameters and runs the createAd banner
     * view action on the UI thread.  If this request is successful, the developer
     * should make the requestAd call to request an ad for the banner.
     *
     * @param options The JSONArray representing input parameters.  This function
     *                expects the first object in the array to be a JSONObject with the
     *                input parameters.
     * @return A PluginResult representing whether or not the banner was created
     * successfully.
     */
    public PluginResult prepareAd(JSONObject options, final CallbackContext callbackContext) {
        CordovaInterface cordova = plugin.cordova;

        plugin.config.setBannerOptions(options);

        cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                CordovaInterface cordova = plugin.cordova;

                if (adView == null) {
                    adView = new AdView(cordova.getActivity());
                    adView.setAdUnitId(plugin.config.getBannerAdUnitId());
                    adView.setAdSize(plugin.config.adSize);

                    Log.i("ivanov-Admob", "==========>>>> banner plugin.config.adSize: " + plugin.config.adSize);

                    adView.setAdListener(new BannerListener(BannerExecutor.this));
                }

                if (adView.getParent() != null) {
                    ((ViewGroup) adView.getParent()).removeView(adView);
                }

                bannerVisible = false;

                adView.loadAd(plugin.buildAdRequest());

                //if (config.autoShowBanner) {
                //    executeShowAd(true, null);
                //}

                Log.w("banner", plugin.config.getBannerAdUnitId());

                callbackContext.success();
            }
        });

        return null;
    }

    /**
     * Parses the request ad input parameters and runs the request ad action on
     * the UI thread.
     *
     * @param options The JSONArray representing input parameters.  This function
     *                expects the first object in the array to be a JSONObject with the
     *                input parameters.
     * @return A PluginResult representing whether or not an ad was requested
     * succcessfully.  Listen for onReceiveAd() and onFailedToReceiveAd()
     * callbacks to see if an ad was successfully retrieved.
     */
    public PluginResult requestAd(JSONObject options, CallbackContext callbackContext) {
        CordovaInterface cordova = plugin.cordova;

        plugin.config.setBannerOptions(options);

        if (adView == null) {
            callbackContext.error("adView is null, call createBannerView first");
            return null;
        }

        final CallbackContext delayCallback = callbackContext;
        cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (adView == null) {
                    return;
                }
                adView.loadAd(plugin.buildAdRequest());

                delayCallback.success();
            }
        });

        return null;
    }

    public PluginResult removeAd(CallbackContext callbackContext) {
        CordovaInterface cordova = plugin.cordova;

        Log.w(TAG, "executeDestroyBannerView");

        final CallbackContext delayCallback = callbackContext;
        cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (adView != null) {
                    ViewGroup parentView = (ViewGroup) adView.getParent();
                    if (parentView != null) {
                        parentView.removeView(adView);
                    }
                    adView.destroy();
                    adView = null;
                }
                bannerVisible = false;

                if (wrapperView != null) {
                    ViewGroup parentView = (ViewGroup) wrapperView.getParent();
                    if (parentView != null) {
                        parentView.removeView(wrapperView);
                    }
                    wrapperView = null;
                }

                delayCallback.success();
            }
        });

        return null;
    }

    /**
     * Parses the show ad input parameters and runs the show ad action on
     * the UI thread.
     *
     * @param show The JSONArray representing input parameters.  This function
     *             expects the first object in the array to be a JSONObject with the
     *             input parameters.
     * @return A PluginResult representing whether or not an ad was requested
     * succcessfully.  Listen for onReceiveAd() and onFailedToReceiveAd()
     * callbacks to see if an ad was successfully retrieved.
     */
    public PluginResult showAd(final boolean show, final CallbackContext callbackContext) {
        CordovaInterface cordova = plugin.cordova;
        bannerShow = show;

        if (adView == null) {
            return new PluginResult(PluginResult.Status.ERROR, "adView is null, call createBannerView first.");
        }

        cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (adView == null) {
                    return;
                }
                CordovaInterface cordova = plugin.cordova;
                if (bannerVisible == bannerShow) {
                    // no change
                } else if (bannerShow) {
                    CordovaWebView webView = plugin.webView;
                    if (adView.getParent() != null) {
                        ((ViewGroup) adView.getParent()).removeView(adView);
                    }
                    ViewGroup wvParentView = (ViewGroup) getWebView().getParent();
                    if (parentView == null) {
                        parentView = new LinearLayout(webView.getContext());
                    }
                    if (wvParentView != null && wvParentView != parentView) {
                        ViewGroup rootView = (ViewGroup)(getWebView().getParent());
                        wvParentView.removeView(getWebView());
                        ((LinearLayout) parentView).setOrientation(LinearLayout.VERTICAL);
                        parentView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0F));
                        getWebView().setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0F));
                        parentView.addView(getWebView());
                        rootView.addView(parentView);
                    }

                    if (wrapperView == null) {
                        wrapperView = new LinearLayout(webView.getContext());

                        final DisplayMetrics displayMetrics = webView.getContext().getResources().getDisplayMetrics();
                        final float webViewHeightDpi = displayMetrics.heightPixels / displayMetrics.density;

                        int dp = 50;
                        if (plugin.config.adSize == AdSize.SMART_BANNER) {
                            if (webViewHeightDpi <= 400) {
                                dp = 32;
                            }
                            else if (webViewHeightDpi <= 720) {
                                dp = 50;
                            }
                            else {
                                dp = 90;
                            }
                        }

                        int adHeight = (int) (dp * displayMetrics.density);

                        wrapperView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, adHeight));

                        parentView.addView(wrapperView);
                        parentView.bringToFront();
                        parentView.requestLayout();
                        parentView.requestFocus();
                    }

                    LinearLayout.LayoutParams adParams = new LinearLayout.LayoutParams(
                        RelativeLayout.LayoutParams.WRAP_CONTENT,
                        RelativeLayout.LayoutParams.WRAP_CONTENT,
                        Gravity.CENTER_HORIZONTAL);

                    wrapperView.addView(adView, adParams);
                    wrapperView.bringToFront();
                    wrapperView.requestLayout();
                    wrapperView.requestFocus();

                    adView.setVisibility(View.VISIBLE);
                    bannerVisible = true;

                } else {
                    adView.setVisibility(View.GONE);
                    bannerVisible = false;
                }

                if (callbackContext != null) {
                    callbackContext.success();
                }
            }
        });

        return null;
    }

    public void pauseAd() {
        if (adView != null) {
            adView.pause();
        }
    }

    public void resumeAd() {
        if (adView != null) {
            adView.resume();
        }
    }

    @Override
    public void destroy() {
        if (adView != null) {
            adView.destroy();
            adView = null;
        }
        if (adViewLayout != null) {
            ViewGroup parentView = (ViewGroup) adViewLayout.getParent();
            if (parentView != null) {
                parentView.removeView(adViewLayout);
            }
            adViewLayout = null;
        }
        if (wrapperView != null) {
            ViewGroup parentView = (ViewGroup) wrapperView.getParent();
            if (parentView != null) {
                parentView.removeView(wrapperView);
            }
            wrapperView = null;
        }
    }

    private View getWebView() {
        CordovaWebView webView = plugin.webView;
        try {
            return (View) webView.getClass().getMethod("getView").invoke(webView);
        } catch (Exception e) {
            return (View) webView;
        }
    }

    boolean shouldAutoShow() {
        return plugin.config.autoShowBanner;
    }
}