I have a working AdMob AdView on top of my opengl game. Its working great but I notice that it keeps showing a particular blank ad. I thought it was a bug on my side but then I noticed that the ad is functioning partially. The ad appears to be a RocketFuel ad according to the provided info button in the top right of the AdView. Clicking within the blank AdView area does nothing unless the info button it hit. The images and code below help explain.
I thought RocketFuel was a separate ad service, is it possible to limit its appearance in Google AdMob using the Filter Settings > Category / Type Settings > Affiliate offers? Or perhaps one of the other categories? I am going to try adding a URL Block for rocketfuel.com under the Ad Filters. However I am unsure if they are serving ads directly from their domain.
Otherwise, is there any way to block, report, or limit these types of ads from being shown through my app? Has anyone had similar problems with such ads?
Here is how I slap the adview on top of my java based OpenGL ES 2 renderer:
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mView = new nopgRenderer(this);
setContentView(mView);
adView = new AdView(this, AdSize.IAB_LEADERBOARD, "<AdMobAdAppID>");
RelativeLayout layout = new RelativeLayout(this);
layout.addView(adView);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.addRule(RelativeLayout.CENTER_HORIZONTAL);
adView.setLayoutParams(params);
this.addContentView(layout, params);
adView.loadAd(new AdRequest());
}
public static void hideAd(){
adView.setVisibility(AdView.GONE);
}
public static void showAd(){
adView.setVisibility(AdView.VISIBLE);
}
The app on Google Play:
https://play.google.com/store/apps/details?id=com.dmtsource.nopg
Example of a normal ad:
Example of the blank ad:
Clicking on the info item in the blank ad:
Related
I recently decided to update my older apps and bring them a little more up to date. In doing so I noticed an odd problem when running them on my new handset (Android O / API Level 29).
My App is essentially a single Activity using OpenGL. This is basically what happens when the app is first loaded...
Create Layout, Create a Splashscreen View, create custom GLSurfaceView
Add GLSurfaceView to Layout
Add Splashscreen to Layout
Start AsyncTask to load resources and do setup ops
GLSurfaceView dismisses Splashscreen to reveal renderer...
So, it all works perfectly well on my older devices (3 x handsets, 1 x tablet all running various versions of Android no higher than Lollipop).
However, on my Android 10 handset, all I get is a blank screen while the app starts. Just to be clear, there are no errors, the app itself works perfectly fine. After the usual startup time, the blank screen is dismissed and the app continues, it's just that the 'splashscreen' has now become a "blankscreen".
But Android Studio Layout Inspector tells a different story
Indeed, if I open the Layout Inspector in Android Studio, oddly it shows exactly what I would expect... the splashscreen with its text/graphics, but not on the actual device...
Some test code
In the following test code I replaced the resource loading / setup with a simple Thread.sleep just to create a longer delay so I could more easily inspect the output in Android Studio. This does still exhibit the problem...
#Override
protected void onCreate(Bundle savedInstanceState) {
int[] deviceResolution = getDeviceResolution();
width = deviceResolution[0];
height = deviceResolution[1];
layout = new RelativeLayout(this);
splash = new Splash(getApplication(), width, height);
myGLView = new CustomGLSurfaceView(this.getApplication());
layout.addView(myGLView);
layout.addView(splash);
setContentView(layout);
loadResource = new LoadResources(newBundle);
loadResources.execute();
super.onCreate(savedInstanceState);
}
class LoadResources AsyncTask<Void, Void, Void> {
Bundle savedBundle;
LoadResources(Bundle savedBundle){
this.savedBundle=savedBundle;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// Simulate some long-running task here. While this is happening, splashscreen should be visible. And on older devices, it is. Not on Android O handset (but OK in Android Studio Layout Inspector).
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Would typically make my calls here to load resources, and complete other setup tasks here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}
** Other observations **
I know that Async is now deprecated and I'm also aware of other Splashscreen tecnhiques such as using a dedicated Activity. However due to the setup/complexity of the apps and given that it doesn't 'break' them per-se, I don't want to have to refactor the entire codebase (just yet anyway) any new apps going forward will use a different system for the splashscreen. What I'm really trying to understand here is why this now doesn't work as it used to. Is this a bug? Or a behavioural change that happened in an Android version somewhere down the line? Or maybe it's just me doing something wrong. If anyone has come across it, I'd be really interested to know of a fix/workaround.
** Other things I've tried **
In the above example, if I simply don't add 'myGLView' then the splashscreen shows, but of course the app then won't work. So I though about adding it in onPostExecute and then bringing the splashscreen view back to the front with splash.bringToFront(). This kind of works, but is messy. The splashscreen only shows for a brief second, and on devices that show it correctly there is a 'glitch' as the correctly displayed splashscreen is overlayed with the GL Renderer and then bought back to the front.
You are adding a view to an object which is not currently set in an Activity.
The better approach would be calling setContentView() first as well as the super method, then adding the multiple views in it.
So in your case, it'll be like:
super.onCreate(savedInstanceState);
setContentView(layout);
layout = new RelativeLayout(this);
int[] deviceResolution = getDeviceResolution();
width = deviceResolution[0];
height = deviceResolution[1];
layout = new RelativeLayout(this);
splash = new Splash(getApplication(), width, height);
myGLView = new CustomGLSurfaceView(this.getApplication());
layout.addView(myGLView);
layout.addView(splash);
loadResource = new LoadResources(newBundle);
loadResources.execute();
I followed a tutorial in connecting to google leaderboard but a lot of tutorials are using the old google play services library. I manage to sign in to google using this code but it appears upon starting the app. Where should I put the googleAPIclient code so that I can log in when I click a button inside the game. I use libgdx and if anyone can link a tutorial that uses a new google play services library It would help a lot. I seemed to be stuck with this one. Thank you!
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create the layout
RelativeLayout layout = new RelativeLayout(this);
// Do the stuff that initialize() would do for you
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
// Create the libgdx View
View gameView = initializeForView(new RBGame(this,this), false);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Plus.API)
.addApi(Games.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Games.SCOPE_GAMES)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
// Create and setup the AdMob view
adView = new AdView(this);
adView.setAdSize(AdSize.BANNER);
adView.setAdUnitId(AD_UNIT_ID);
AdRequest adRequest = new AdRequest.Builder().build();
adView.loadAd(adRequest);
// Add the libgdx view
layout.addView(gameView);
// Add the AdMob view
RelativeLayout.LayoutParams adParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
adParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
adParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
//layout.addView(adView, adParams);
// Hook it all up
setContentView(layout);
}
Easiest way to get it going is to use BaseGameUtils which you can download here (it is located in /BasicSamples/libraries/).
The Google Play Game Services documentation describes how to use it. You still don't have to use BaseGameUtils, you could just use it as a reference for coding your own. But using it seems to be the way Google wants it done - probably to provide some consistency across games :)
Personally, I don't like using the BaseGameActivity as a base for my own activities and allowing it to take over the sign-in flow completely. I just use the GameHelper class to perform the required functionality on demand.
My App, (OpenGL ES 2.0) currently has 55 classes, and one activity single.
I have my own custom Scene Manager which I use to change between different Scenes (ie, different scenes would be: Main Menu, Level Select, Level 1, Level 2....Level 20, Game Over etc...)
So I set all of my AdMob stuff up in my Activity's onCreate(); method. So at the moment, the same ad runs throughout the whole app.
How it is possible to 'switch off' the ads on different Scenes?
Bear in mind that none of my classes have direct access to the Activity class itself.
Any suggestions would be appreciated as I'm finding using AdMob extremely challenging, it doesn't seem very intuitive so any AdMob experts out there, your opinions would be appreciated!
I should point out that I don't use XML, everything is done programmatically.
Thanks
Code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create an ad.
adView = new AdView(this);
adView.setAdSize(AdSize.BANNER);
adView.setAdUnitId(AD_UNIT_ID);
// Add the AdView to the view hierarchy. The view will have no size
// until the ad is loaded.
RelativeLayout layout = new RelativeLayout(this);
layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
// Create an ad request. Check logcat output for the hashed device ID to
// get test ads on a physical device.
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(TestDeviceID)
.build();
// Start loading the ad in the background.
adView.loadAd(adRequest);
//Request full screen
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
//Create a displayMetrics object to get pixel width and height
metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
width = metrics.widthPixels;
height = metrics.heightPixels;
//Work out values for resizing screen while keeping aspect ratio
width = (int) Math.min(width, height * 1.702127659574468);
height = (int) Math.min(height, width / 1.702127659574468);
//Create and set GL view (OpenGL View)
myView = new MyGLSurfaceView(MainActivity.this);
RelativeLayout.LayoutParams adParams =
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
adParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
adParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
//Set the colour if we don't, the ad won't show (bug?)
adView.setBackgroundColor(Color.BLACK);
layout.addView(myView);
layout.addView(adView, adParams);
//Create a copy of the Bundle
if (savedInstanceState != null){
newBundle = new Bundle(savedInstanceState);
}
setContentView(layout);
}
First of all you're causing yourself a lot of pain by doing your layout programmatically (I gave a talk on this just last night). You should really consider understanding and using the XML layout.
But to answer your question, you will need to find a way for the classes that want to control whether an ad is shown or not to have some method of sending a message to the Activity. I would suggest injecting them with an interface that is implemented by an inner classes in your Activity.
The interface is going to need to look something like:
- startShowingAds - this should start requesting ads and make the AdView visible.
- stopShowingAds - this should pause ad showing and hide the AdView.
To temporarily hide the ads you just need to hide the AdView, eventually calling pause() even though I think that hidden ad views are not refreshed (you can check in the logs).
About how to reach the AdView object from your code, it depends on what you have accessible from there. If you just have the View where you are drawing a solution could be to store the AdView object in the View's tag (see setTag() and getTag() here: https://developer.android.com/reference/android/view/View.html#getTag%28int%29).
My application consists of a MapActivity, which loads an XML view (map_layout), containing a MapView and a CustomView which extends ImageView.
I use the following code to setup my MapActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_layout);
initialise();
}
Then in initialise, I retrieve the MapView and CustomView from the XML file using findViewById(...) as usual. Within the onMeasure(...) function of my CustomView I use this.getWidth() and this.getHeight() to get its dimensions, which returns the correct results.
Then within my initialise() code I decided to check if GPS is enabled (using code similar to the first answer here: How do I find out if the GPS of an Android device is enabled), showing an AlertDialog if GPS is disabled.
The problem is now that the onMeasure(...) function of my CustomView no longer works correctly, and this.getWidth() and this.getHeight() both return 0 if the AlertDialog gets displayed.
Why is this the case?
Thanks for your help in advance, if my question is unclear I'll edit it to add the full code when I have chance.
Okay, I needed to get the height and width within onLayout() instead of onMeasure() for some reason.
Is there any way to always show zoom controls in webview?
I found this: Always show zoom controls on a MapView
but that's for the mapview.
I want them to always be visible.
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
WebSettings ws = super.appView.getSettings();
ws.setSupportZoom(true);
ws.setBuiltInZoomControls(true);
setDisplayZoomControls() is only available from API 11 (Android 3). So you can't even consider using it until the vast majority of Android devices are 3 or above - which will not be for some years :(
Not sure if this will work as I never tried, but I checked the reference in developer.android.com
ws.setDisplayZoomControls(true);
If this worked dont forget to best answer this answer.
Also check this out:
http://www.tutorialforandroid.com/2009/02/webview-with-zoomcontrols-in-android.html
good tutorial. (Debunks my theory)
None of the above worked for my. Only when I start draging the webview content the controls show up the first time. So what I did as a "quick fix" is in onStart() of my Fragment that holds the Dialog with the webview I call:
webview.invokeZoomPicker();
Example:
#Override
public void onStart(){
super.onStart();
DialogFragment dialog = this;
//...stuff
if(dialog.getDialog()!= null && dialog.getDialog().getWindow()!=null){
//...more stuff
View v = dialog.getView();
if(v!=null){
//invoke controls on start once, they stay active a few seconds:
WebView webview =v.findViewById(R.id.frag_dlg_WebView);
webview.invokeZoomPicker();
}
}
}
The controls light up only for a few seconds until they disappear again, by then the user in my case should have dragged the webview already.