Showing posts with label Manager. Show all posts
Showing posts with label Manager. Show all posts

Sunday, March 10, 2013

Shards - Work In Progress I



This is short info on our upcoming game - Shards - we are working on. The game will be clone of well known arcade classic with glassy look and very nice fractal backgrounds. The music in video is just a placeholder I found on the web - it sounds to make me sure the sound engine works.


 Making the game we are using these technologies:
  • box2D for physics,
  • notice the usage of our universal box2D debug draw that works for Open GL ES 1.x and 2.0,
  • our cross platform engine -  the video is taken from desktop Windows while the game runs on Android as well,
  • PicOpt - our sprite atlas creation tool that is free to download,
  • for Android NDK: textures are loaded through this way, while sound (not too much of them in the game presently) is coded like this,
  • for ads we plan to utilize our simple ads manager.

Tuesday, March 5, 2013

Creating Ads Manger for Android - Part 5 - Implementing Leadbolt





previous parts

 In previous part we implemented Madvertise. This time we will do the same with Leadbolt. While AdMob and Madvertise pays you for click, Leadbolt pays you usually for action the user has to do. So you may encounter CPA term which stands for Cost per Action instead well known CPC (cost per Click). If I convert my latest revenue to CPC I get very low value 0.01 - 0.02 while AdMob is 0.035 in average. Beside this Zone Alarm for Android is warning users that your app contains AdwareAndroidos.leadbold... Is it still worth to implement it? Ok, I am using only banners, not any kind of ads like push notifications and so on, so my users will not get angry. The app passed registration at Slideme.org or Amazon.com without problems. And the size of the banner is smaller than AdMob or Madvertise banners. Thus, for our game Deadly Abyss 2 is Leadbolt only network if playing on mobile phone (if playing on tablet then AdMob, Madvertise and Leadbolt are rotating).
 Finally, we are making ad manager to handle multiple networks, so it is not wise to rely only on one network.
 If you intent to use Leadbolt you can register through this link. If you do so, I will get some small reward from them :-)

Adding Leadbolt SDK

 This should be no problem. Leadbolt has very good and simple manual. It is located under App Developer SDKs in HELP/FAQS section. Actually it is the same as AdMob integration - copy .jar with SDK into libs folder and then adjust Build Path in Project Properties (right click on project name in Eclipse). Then Add JARs...


Adjusting manifest

 As for previous ad networks we have to adjust manifest file with permissions. Leadbolt has three required permissions: INTERNET, ACCESS_NETWORK_STATE and READ_PHONE_STATE. The first two we already have from times of AdMob implementation. There are three optional permissions: ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION and ACCESS_ LOCATION_EXTRA_COMMANDS. The coarse location we already allowed for Madvertise so we adjust the manifest like this:

  <!-- additional LeadBolt permissions -->
  <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 
  <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/> 


Adjusting constatns

 While most of the other networks has some way how to set refresh rate for Leadbolt you have to do it by yourself. So in the file with constants (SBCAdsConstatnts.java) we will define these lines:

 // Leadbolt
 public static final String LEADBOLT_UNIT_ID = "YOUR_LEADBOLT_ID_HERE";
 public static final long LEADBOLT_REFRESH_RATE = 1000 * 90 * 1;

 The first line contains the ID your ad unit is assigned by Leadbolt. The second line defines refresh rate in millis - here 1,5 minute.


LeadboltSystem.java

 Now let's start implementation. As usual the imports and fields come first:

package com.sbcgames.sbcads;import com.pad.android.iappad.AdController;import com.pad.android.listener.AdListener;import com.sbcgames.sbcengine.SBCEngine;import android.util.Log;import android.view.KeyEvent;import android.view.ViewGroup;public class LeadboltSystem implements SBCAdSystem, AdListener
{
 private final String SYSTEM_NAME = "LEADBOLT ";
 private SBCAdEventListener mListener = null;
 private AdController mAdView;
 private final ViewGroup mLayout;
 private Runnable mR = null;
 private SBCEngine mSBCEngine = null;

 The constructor is very simple:

 // ------------------------------------------------------------------------
 public LeadboltSystem(SBCEngine aSBCEngine, ViewGroup aLayout)
 {
  mSBCEngine = aSBCEngine;
  mLayout = aLayout;
 }


SBCAdSystem implementation

 Next follows implementation of our SBCAdSystem interface:

 //------------------------------------------------------------------------
 // SBCAdSystem
 //------------------------------------------------------------------------
 @Override
 public void start()
 {
  final LeadboltSystem system = this;

  mR = new Runnable()
  {
   public void run()
   {
    Log.d("AdsSystem", SYSTEM_NAME + "Creating AdController and asking for Ad");

    if (mAdView != null)
    {
     stop();
     destroy();
     mAdView = null;
    }
    
    mAdView = new AdController(mSBCEngine, SBCAdsConstants.LEADBOLT_UNIT_ID, system);
    mAdView.loadAd();
    
    mLayout.postDelayed(this, SBCAdsConstants.LEADBOLT_REFRESH_RATE);
   }
  };

  mLayout.postDelayed(mR, 0);
 }

 Here is problem that I encountered: to refresh ad, calling to destroyAd() (called in destroy() method) and then calling to loadAd() should be enough. But the refreshing in this way did not work for me. So I am destroying the mAdView (the AdController object) every time and creating new one. I posted question to forum and I got reply from user called jay-z. While the above method works, I will try his code and update this article accordingly if it will work for me too.

 Here is implementation of next methods - nothing special here:

 //------------------------------------------------------------------------
 @Override
 public void stop()
 {
  if (mR != null)
  {
   Log.d("AdsSystem", SYSTEM_NAME + "removing listener");
   mLayout.removeCallbacks(mR);
  }
 }

 //------------------------------------------------------------------------
 @Override
 public void destroy()
 {
  if (mAdView != null)
  {
   mAdView.destroyAd();
  }
 }

 //------------------------------------------------------------------------
 @Override
 public void setEventListener(SBCAdEventListener aListener)
 {
  mListener = aListener;
 }

 In last two parts when implementing AdMob and Madvertise we left our keyDown implementation empty. For Leadbolt we have to handle back key. This is the reason why we have this method in interface. Of course, to avoid implementation in every ad system we could create abstract class between interface and concrete implementation (that will do nothing) and override it only when we need specialised behavior - I will leave this small change on your choice:

 //------------------------------------------------------------------------
 @Override
 public boolean keyDown(final int aKeyCode, final KeyEvent aEvent)
 {
  if (aKeyCode == KeyEvent.KEYCODE_BACK)
  {
   if (mAdView.onBackPressed())
   {
    Log.d("AdsSystem", SYSTEM_NAME + "back key pressed");
    return true;
   }
  }
  
  return false;
 }


AdListener implementation

 Leadbolt, as well as other ad networks we have seen so far has its own interface for callbacks. The name is AdListener - the same as for AdMob. But this time it has different set of methods. Their implementation is empty for most of the them. The one that is important is onAdClicked(). Despite AdMob or Madvertise, the Leadbolt does not start any new Activity that would pause your current activity - your game. So, you have to do it by yourself. We are calling sendMessage() method. This method is general method in my engine to send messages to Java part of the engine from other Java parts or from NDK. Thanks to this I can ask engine to do lot of things just with different method's arguments.

 //------------------------------------------------------------------------
 // LEADBOLT
 //------------------------------------------------------------------------
 @Override
 public void onAdClicked()
 {
  stop();
  mSBCEngine.sendMessage(SBCEngine.MESSAGE_OUT_PAUSE, 0, 0);
  Log.d("AdsSystem", SYSTEM_NAME + "onAdClicked");
 }
 
 //------------------------------------------------------------------------
 @Override
 public void onAdAlreadyCompleted()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdAlreadyCompleted");
 }
  
 //------------------------------------------------------------------------
 @Override
 public void onAdClosed()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdClosed");
 }

 //------------------------------------------------------------------------
 @Override
 public void onAdCompleted()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdCompleted");
 }

 //------------------------------------------------------------------------
 @Override
 public void onAdFailed()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdFailed");
  mListener.onFailed(this);
 }

 //------------------------------------------------------------------------
 @Override
 public void onAdHidden()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdHidden");
 }

 //------------------------------------------------------------------------
 @Override
 public void onAdLoaded()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdLoaded");
 }

 //------------------------------------------------------------------------
 @Override
 public void onAdPaused()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdPaused");
 }

 //------------------------------------------------------------------------
 @Override
 public void onAdProgress()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdProgress");
 }

 //------------------------------------------------------------------------
 @Override
 public void onAdResumed()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdResumed");
 }}


Conclusion

 This is all for Leadbolt implementation. This was also last part of this little series. We created simple but extensible ad manager. Now it is up to you to enhance it and add other ad networks.



Sunday, March 3, 2013

Creating Ads Manger for Android - Part 4 - Implementing Madvertise





previous parts


Last time we implemented first ad network - AdMob. Today we will add Madvertise. This network is exactly the reason why we are building some ad systems manager. It seems that Madvertise is focused on some countries of western Europe - Germany, Italy. Earnings are about 0,05 EUR / click, which is not bad. But if your user is in any other location they will not send an ad into his device. This results into low fill rate but if you have ad manager you can just say never mind and skip to other ad network.


Adding Madvertise SDK

 To integrate Madvertise SDK into your Eclipse project follow the instructions here. It is enough to follow the instructions until you added Madvertise project into your project as rest may be little bit different for out adds manager.


Adjusting manifest

 Last time we already added permissions for INTERNET and ACCESS_NETWORK_STATE. Today we will add optional permissions for reading state of wifi and to roughly detect the location of the user.

    <!-- additional Madvertise permissions -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

 Next we need to adjust the manifest file with Madvertise activity. There is also place for token identifying your app. If you just want to test then put word "TestTokn" there. Do not forget to replace it when you are ready to publish.

        <activity android:name="de.madvertise.android.sdk.MadvertiseActivity" />

        <!-- Setup your site token. For tests, use 'TestTokn' -->
        <meta-data
            android:name="madvertise_site_token"
            android:value="TestTokn" />


Adjusting constants

 When implementing AdMob we had to adjust file SBCAdsConstants.java with AdMob ad unit ID. This is not necessary here as we put our Madvertise ad ID directly into manifest file.


MadvertiseSystem.java

 Now  we are ready to implement the class. We start with imports and variables again:

package com.sbcgames.sbcads;

import com.sbcgames.sbcengine.SBCEngine;

import de.madvertise.android.sdk.MadvertiseView;
import de.madvertise.android.sdk.MadvertiseView.MadvertiseViewCallbackListener;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;

public class MadvertiseSystem implements SBCAdSystem, MadvertiseViewCallbackListener
{
 private final String SYSTEM_NAME = "MADVERTISE ";
 private SBCAdEventListener mListener = null;
 private MadvertiseView mAdView;
 private ViewGroup mLayout;

 Instead of AdMob AdListener we are implementing MadvertiseViewCallbackListener this time. SBCAdSystem is our interface that we have to implement for every ad network we want our ad manager to handle. This is the constructor:

 // ------------------------------------------------------------------------
 public MadvertiseSystem(SBCEngine aSBCEngine, ViewGroup aLayout)
 {
  mLayout = aLayout;

  // new view - all defaults
  mAdView = new MadvertiseView(aSBCEngine.getApplicationContext());

  // set the AdListener.
  mAdView.setMadvertiseViewCallbackListener(this);
  
  // Add the AdView to the view hierarchy. The view will have no size until the ad is loaded.
  aLayout.addView(mAdView);
 }


SBCAdSystem implementation

 To start Madvertise ad network we have to implement start method from SBCAdSystem interface:

 //------------------------------------------------------------------------
 @Override
 public void start()
 {
     mAdView.setVisibility(View.VISIBLE);

     // Start loading the ad in the background.
     mAdView.setFetchingAdsEnabled(true);
 }

 Calling setFetchingAdsEnabled with true will launch our request for ad. With the result of this reqest we will be notified through MadvertiseViewCallbackListener methods.

 Next we need methods to stop and destroy this ad system in case we are switching to another one.

 //------------------------------------------------------------------------
 @Override
 public void stop()
 {
  if (mAdView != null)
  {
   mAdView.setFetchingAdsEnabled(false);
   mAdView.setVisibility(View.GONE);
  }
 }

 //------------------------------------------------------------------------
 @Override
 public void destroy()
 {
  if (mAdView != null)
  {
   mAdView.removeMadViewCallbackListener();
  }
  mLayout.removeAllViews();
 }

 Finally there is method for setting the events listener and for processing keys. The later will again have no implementation for Madvertise:

 //------------------------------------------------------------------------
 @Override
 public void setEventListener(SBCAdEventListener aListener)
 {
  mListener = aListener;
 }
 
 //------------------------------------------------------------------------
 @Override
 public boolean keyDown(final int aKeyCode, final KeyEvent aEvent)
 {
  return false;
 }


MadvertiseViewCallbackListener implementation

 Now comes the implementation of the interface that is part of Madvertise SDK. Again it is very simple as most of the methods will just notify our listener (that means our ad manager that is implementing it) and the rest is more or less just some debug output to watch in LogCat if everything is going well.

 //------------------------------------------------------------------------
 // MadvertiseViewCallbackListener
 //------------------------------------------------------------------------
 @Override
 public void onLoaded(boolean succeed, MadvertiseView madView)
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onLoaded");
  
  if (!succeed)
  {
   mListener.onFailed(this);
  }
 }
 
 //------------------------------------------------------------------------
 @Override
 public void onError(Exception exception)
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onError");
  
  mListener.onFailed(this);
 }

 //------------------------------------------------------------------------
 @Override
 public void onIllegalHttpStatusCode(int statusCode, String message)
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onIllegalHttpStatusCode");
 }

 //------------------------------------------------------------------------
 @Override
 public void onAdClicked()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onAdClicked");
 }

 //------------------------------------------------------------------------
 @Override
 public void onApplicationPause()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onApplicationPause");
 }

 //------------------------------------------------------------------------
 @Override
 public void onApplicationResume()
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onApplicationResume");
 }


Conclusion

  Today we added next ad network to our ad manager system. Next time we will ad Leadbolt network. You can now adjust the constants in SBCAdsConstants.java file so it handles two networks and with probability settings you can say how many percent of your users will ask for AdMob or Madvertise ad.



Tuesday, February 19, 2013

Creating Ads Manger for Android - Part 3 - Implementing AdMob



previous parts



 In Part 2 we finished our SBCAdManager class. Now we have system that will choose the right ad network for us as well as check whether the network is alive (sending ads) and change to another one if the network is dead. But so far we did not implement any ad network. As was said in previous parts we will step by step implement AdMob, Madvertise and Leadbolt. The system we are developing in this series is working in our real games Deadly Abyss 2 and Mahjong Tris.

 This time we will implement first of the ad networks - AdMob. (for clarity, I am using terms ad network and ad system interchangeably)


SBCAdSystem interface

 To provide common set of methods to control each of the implemented ad systems we will introduce interface class SBCAdSystem. In each of the ad systems in our ad engine we will implement the methods. Remember Part 1 and picture with all the files in com.sbcgames.sbcads package. The interface is in SBCAdSystem.java file:

package com.sbcgames.sbcads;

import android.view.KeyEvent;

public interface SBCAdSystem
{
 public void start();
 public void stop();
 public void destroy();
 public void setEventListener(SBCAdEventListener aListener);
 public boolean keyDown(final int aKeyCode, final KeyEvent aEvent);
}


Adding AdMob SDK

 Go to  Google Developers site to get the latest version of SDK. Or you may have it already as a part of downloaded SDK in "extras" directory (mine path is: D:\Android\android-sdk\extras\google\admob_ads_sdk\). To incorporate it into your project follow steps 1-3 at Google Developers (do not forget to choose "Android" in the top of the page or you will see iOS related how-to).


Adjusting manifest

 Every Ad network needs some permissions enabled. AdMob is not as hungry as other so internet access and network state reading is enough. Put the following lines into your manifest file:

    <!-- AdMob SDK requires Internet permission -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

 You also need to define AdMob activity inside your application tag:

        <!-- AdMobActivity definition -->
        <activity
            android:name="com.google.ads.AdActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />


Adjusting constants

 Next we will adjust our file with constants (file SBCAdsConstatns.java) . I am again referring to Part 1 where the file is listed. Bellow is only the line related to AdMob implementation. Replace the text of the constant with the ID you get from AdMob site after you register your app - click Manage Settings and you should see something like this:

 // AdMob
 public static final String ADMOB_AD_UNIT_ID = "your admob unit id here";


AdMobSystem.java

 Now you are ready to  real implementation. Start with imports and variables:

package com.sbcgames.sbcads;

import com.google.ads.*;
import com.google.ads.AdRequest.ErrorCode;
import com.sbcgames.sbcengine.SBCEngine;

import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;

public class AdMobSystem implements SBCAdSystem, AdListener
{
 private final String SYSTEM_NAME = "ADMOB ";
 private SBCAdEventListener mListener = null;
 private AdView mAdView;
 private ViewGroup mLayout;

 The class implements SBCAdSystem interface as well as AdListener interface. The AdListener interface is part of AdMob package and its implementation will work as callback for various events like when the ad is received or when the request for ad failed. Our interface is here to unify the different ad systems and to provide some common set of methods to start, stop and so on the system.

 The constructor looks like this:

 // ------------------------------------------------------------------------
 public AdMobSystem(SBCEngine aSBCEngine, ViewGroup aLayout)
 {
  mLayout = aLayout;
  
  // new view
  mAdView = new AdView(aSBCEngine, AdSize.BANNER, SBCAdsConstants.ADMOB_AD_UNIT_ID);
  mAdView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
  
  // set the AdListener.
  mAdView.setAdListener(this);

  // Add the AdView to the view hierarchy. The view will have no size until the ad is loaded.
  aLayout.addView(mAdView);
 }
 
 We store the reference to aLayout which is "adsholder" element in our main.xml layout file. This file we created in first part. Next we create new ad view - this comes from AdMob SDK. We add listener to it - it is the AdListener interface implementation and finally we add this new view into prepared "adsholder" in layout.

 Now the object is created but we have to ask for ad. This is done in start method:

 //------------------------------------------------------------------------
 // SBCAdSystem
 //------------------------------------------------------------------------
 @Override
 public void start()
 {
     mAdView.setVisibility(View.VISIBLE);

     // Create an ad request. Check logcat output for the hashed device ID to
     // get test ads on a physical device.
     AdRequest adRequest = new AdRequest();
     adRequest.addTestDevice(AdRequest.TEST_EMULATOR);
     //adRequest.addTestDevice("YOUR-DEVICE-ID");

     // Start loading the ad in the background.
     mAdView.loadAd(adRequest);
 }

 We first set view to be visible. Then we create request for AdMob ad. In following lines we can add test devices. I highly recommend this as this will deliver test ads into your device so clicking on them will not violate ad company policy. You can add the emulator as well as real devices you are testing your apps on.
 Finally we launch our request. You will be notified if it is or is not successful through AdListener interface implementation.


SBCAdSystem implementation

 The following 5 methods are implementation of SBCAdSystem interface.

 As we want to change from one ad network to another, we need a way how to stop and destroy the ad view:

 //------------------------------------------------------------------------
 @Override
 public void stop()
 {
  if (mAdView != null)
  {
   mAdView.stopLoading();
   mAdView.setVisibility(View.GONE);
  }
 }

 //------------------------------------------------------------------------
 @Override
 public void destroy()
 {
  if (mAdView != null)
   mAdView.destroy();
  mLayout.removeAllViews();
 }

 These two methods are the ones called from SBCAdManager from stopAndDestroyAdSystem() method. It will disable displaying the view and cancel pending requests for ads. And in destroy() method it will destroy the ad view and remove it from "adsholder", so it is empty again and ready to hold any other ad view.

 Last two methods from SBCAdSystem Interface are setEventListener() and keyDown(). The later has no implementation for AdMob, so we just say that AdMob did not consumed the sent key. The first one sets listener for events of this system. The listener is SBCAdManager class itself - it will listen for events from each ad system and based on it it will terminate network, change to another and so on:

 //------------------------------------------------------------------------
 @Override
 public void setEventListener(SBCAdEventListener aListener)
 {
  mListener = aListener;
 }
 
 //------------------------------------------------------------------------
 @Override
 public boolean keyDown(final int aKeyCode, final KeyEvent aEvent)
 {
  return false;
 }


AdListener implementation

 The implementation of Adlistener, the interface that comes with AdMob SDK is easy. In most of the methods only some debug print is implemented. Events which are reported is ad request failure and success. It is reported to listener, which is SBCAdManger. When loading of ad fails it can then stop and destroy this ad network and start another.

 //------------------------------------------------------------------------
 // AdListener
 //------------------------------------------------------------------------
 @Override
 public void onDismissScreen(Ad aAd)
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onDismissScreen");
 }

 //------------------------------------------------------------------------
 @Override
 public void onFailedToReceiveAd(Ad aAd, ErrorCode aErrorCode)
 {
  String message = SYSTEM_NAME + "onFailedToReceiveAd (" + aErrorCode + ")";
  Log.d("AdsSystem", message);
  
  mListener.onFailed(this);
 }

 //------------------------------------------------------------------------
 @Override
 public void onLeaveApplication(Ad aAd)
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onLeaveApplication");
 }
 
 //------------------------------------------------------------------------
 @Override
 public void onPresentScreen(Ad aAd)
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onPresentScreen");
 }

 //------------------------------------------------------------------------
 @Override
 public void onReceiveAd(Ad aAd)
 {
  Log.d("AdsSystem", SYSTEM_NAME + "onReceiveAd");
  mListener.onReceived(this);
 }
}


Conclusion

 For now we have completed ad manager and also first ad network it manages. Next time I will write how to implement Madvertise or Leadbolt network.



Wednesday, February 13, 2013

Creating Ads Manger for Android - Part 2 - Finishing SBCAdManager




previous parts

 Last time we started building of our ads manager, the class that will handle for you woking with ad networks. So far we set our layout, defined some settings and started the SBCAdManager class. Today we will finish it and in next parts we will implement three ad providers - AdMob, Madvertise and Leadbolt.

Construction od SBCAdManager


 Ok, let's go for SBCAdManager constructor:

 public SBCAdManager(SBCEngine aSBCEngine, ViewGroup aLayout)
 {
  mSBCEngine = aSBCEngine;
  mLayout = aLayout;
  
  float dp = aSBCEngine.getApplicationContext().getResources().getDisplayMetrics().density;
  DisplayMetrics dm = new DisplayMetrics(); 
  aSBCEngine.getWindowManager().getDefaultDisplay().getMetrics(dm); 
  int screenWidth = dm.widthPixels; 
  
  //Log.d("AdsSystem", "density:" + dp + " screenwidth:" + screenWidth);
  
  if (screenWidth > 800 && dp <= 1.0f)
  {
   mSystems = SBCAdsConstants.systemsBig;
   mProbability = SBCAdsConstants.probabilityBig;
   mSystemsNames = SBCAdsConstants.systemsNamesBig;
  }
  else
  {
   mSystems = SBCAdsConstants.systemsSmall;
   mProbability = SBCAdsConstants.probabilitySmall;
   mSystemsNames = SBCAdsConstants.systemsNamesSmall;
  }

  mSystemStatus = new SBCAdSystemStatus[mSystems.length];
  
  for (int i = 0; i < mSystemStatus.length; i++)
   mSystemStatus[i] = new SBCAdSystemStatus();
 }

 The initialization part is little bit longer than it necessary has to be. As I last time mentioned we had to choose two "configurations" for our Deadly Abyss 2 game - one for small screens and one for large screens. In constructor you can see we are measuring the size of the display and choosing the appropriate config for it. I left the code here as you can do the same or even more select different sizes of ads from your provider based on screen resolution.
 After that I am creating array of statuses for all ad systems. Statuses were aso explained last time. Its purpouse is to keep information on which ad network failed in sending ad and how long time ago it was. These information are then used when selecting ad network and the time is used to automatically revive failed ad network after some time.

Starting and stopping the Ad Manager


 Now we created the object. Before I show the start() method here is stop() method and also stopAndDestroyAdSystem() method.

 // ------------------------------------------------------------------------
 public void stop()
 {
  Log.d("AdsSystem", "stopping AdsSystem");
  
  // prevent repeated stopping
  if (mStatus == eState.STOPPED)
  {
   Log.d("AdsSystem", "AdsSystem already stopped");
   return;
  }
  
  if (mSBCAdSystem != null)
  {
   stopAndDestroyAdSystem();
  }
  
  mStatus = eState.STOPPED;
 }
 
 // ------------------------------------------------------------------------
 public void stopAndDestroyAdSystem()
 {
  if (mSBCAdSystem != null)
  {
   mSBCAdSystem.stop();
   mSBCAdSystem.destroy();
   mSBCAdSystem = null;
  }
 }

 It first checks whether the manager itself is in running state and if yes it then checks if some ad system is running. If yas again, the runnin ad system is destroyed and then also the SBCAdManaget is put into STOPPED state.

 Start() method looks like this:

 public void start()
 {
  Log.d("AdsSystem", "starting AdsSystem");
  
  // prevent repeated starting
  if (mStatus == eState.RUNNING)
  {
   Log.d("AdsSystem", "AdsSystem already started");
   return;
  }
  
  if (mSBCAdSystem == null)
   setAdSystem(); 

  if (mSBCAdSystem != null)
   mSBCAdSystem.start();
  
  mStatus = eState.RUNNING;
 }

 First it checks whether the manager was already started and if not new system is set. As the setAdSystem may set no ad network (for example if the user is offline) the result  is checked and if not null then the selected ad system is started.


Selecting the ad system


 The setAdSystem() method is the place where several things happen:
  • first it is checked if the user is online,
  • then reviveAdSystems is called to revive dead ad system - the ones that failed to deliver ads in past time,
  • new system is chosen,
  • based on result new ad system object is created and SBCAdManager is set as object that is listening for its events (events like - user clicked ad, ad request failed, ...)
 private void setAdSystem()
 {
  if (!isOnline())
  {
   Log.d("AdsSystem", "system is off-line");
   return;
  }
 
  Log.d("AdsSystem", "selecting new ad system");
  
  reviveAdSystems();

  int newSystem = chooseAdSystem();
  if (newSystem == -1)
  {
   mSBCAdSystem = null;
   mLastSBCAdSystem = -1;
   return;
  }
  
  switch (newSystem)
  {
  case SBCAdsConstants.ADMOB:
   mSBCAdSystem = new AdMobSystem(mSBCEngine, mLayout);
   Log.d("AdsSystem", "AdMob selected");
   break;
  
  case SBCAdsConstants.MADVERTISE:
   mSBCAdSystem = new MadvertiseSystem(mSBCEngine, mLayout);
   Log.d("AdsSystem", "Madvertise selected");
   break;
  
  case SBCAdsConstants.LEADBOLT:
   mSBCAdSystem = new LeadboltSystem(mSBCEngine, mLayout);
   Log.d("AdsSystem", "Leadbolt selected");
   break;
  }
  
  mLastSBCAdSystem = newSystem;
  if (mSBCAdSystem != null)
   mSBCAdSystem.setEventListener(this);
 }

 The isOnLine() method is short helper returning true or false:

 private boolean isOnline()
 {
  ConnectivityManager cm = (ConnectivityManager) 
    mSBCEngine.getSystemService(Context.CONNECTIVITY_SERVICE);
  NetworkInfo nInfo = cm.getActiveNetworkInfo();
  return (nInfo != null && nInfo.isAvailable() && nInfo.isConnected());
 }

 More interesting are other two methods - reviveAdSystem() and chooseAdSystem(). The first one has listing like this:

 private void reviveAdSystems()
 {
  int systemsCount = mSystems.length;
  
  // revive all systems that failed before some time
  long currentTime = System.currentTimeMillis();
  for (int i = 0; i < systemsCount; i++)
  {
   SBCAdSystemStatus status = mSystemStatus[i];
   
   if (status.isFailed() && 
     currentTime - status.getFailedTime() > SBCAdsConstants.REVIVE_TIME)
   {
    Log.d("AdsSystem", "Reviving system " + mSystemsNames[i]);
    status.setFailedTime(0);
    status.setFailed(false);
   }
  }
 }

 It simply goes through statuses of all systems and if the system is marked as failed then it cheks time when the ad system fialed. If it is in past long time ago enough the system is marked as live again and so ready for selection.

 chooseAdSystem() method first gets random number from 0 to 99. It then loops through your configuration take from constant and set in constructor. Based on this it finds ad network. If the network is dead - it's status isFailed() is true. then it loops through othe ad networks starting with next one. If the loop completes and you return to first selected network it means that all networks are dead. In such  case null is returned. Otherwise index of selected live ad system is returned.

 private int chooseAdSystem()
 {
  int result = -1;
  int systemsCount = mSystems.length;
  
  int prob = mRnd.nextInt(100);
  int cumul = 0;
  for (int i = 0; i < systemsCount; i++)
  {
   cumul += mProbability[i];

   // possible system - check for last failures 
   if (prob < cumul)
   {
    // chosen system failed in last 2 minutes - choose next 
    if (mSystemStatus[i].isFailed())
    {
     int idx = i + 1;
     while (idx != i)
     {
      if (idx >= systemsCount)
       idx = 0;
      
      if (!mSystemStatus[idx].isFailed())
      {
       result = mSystems[idx];
       break;
      }
      
      ++ idx;
     }
    }
    else
    {
     result = mSystems[i]; 
    }
    
    break;
   }
  }
  
  return result;
 }


Callbacks - SBCAdEventListener


 In the end of setAdSystem() method we set listener for events comming from ad network. As the listener we set SBCAdEventListener interface that is implemented by SBCAdSystem class. The interface methods are callbacks that are called when some event in ad system occures. The implementation of them is like this:

 // ------------------------------------------------------------------------
 // CALLBACKS 
 // ------------------------------------------------------------------------
 public void onClick(SBCAdSystem aSBCAdSystem)
 {
 }

 // ------------------------------------------------------------------------
 public void onReceived(SBCAdSystem aSBCAdSystem)
 {
 }

 // ------------------------------------------------------------------------
 public void onFailed(SBCAdSystem aSBCAdSystem)
 {
  if (aSBCAdSystem == mSBCAdSystem)
  {
   if (mLastSBCAdSystem != -1)
   {
    // mark this system as failing
    mSystemStatus[mLastSBCAdSystem].setFailed(true);
    mSystemStatus[mLastSBCAdSystem].setFailedTime(System.currentTimeMillis());
   }
   changeAdSystem();
  }
 }

 As you can see, currently I have only onFailed implemented. If the ad system says that it failed I just mark it as dead. I record the time of death and try to chnge the system with changeAdSystem() method which has this listing:

 private void changeAdSystem()
 {
  long delayTime = allAdSystemsFailed() ? SBCAdsConstants.NEXT_TRY_TIME : 0;
  
  Log.d("AdsSystem", "Change Ad System in " + delayTime + " millis");
  
  mHandler.postDelayed((new Runnable()
  {
   @Override
   public void run()
   {
    Log.d("AdsSystem", "Changing ad system");
    if (mSBCAdSystem != null)
    {
     stopAndDestroyAdSystem();
    }

    setAdSystem();
    if (mSBCAdSystem != null)
     mSBCAdSystem.start();
   }
  }), delayTime);
 }

 This is kind of thin ice for me as I am not too experienced Java/Android coder. So, any improvements or suggestions are welcome. What the mehod does is that it first calculates when the system should change - immediately or if all systems are dead than after time defined in constatnts (I use 2 minutes). Next the actual ad system changing method is scheduled. It deletes any previous ad system sets new and starts it.

 For completness here is also the allAdSystemsFailed() method. As the name says it just returns true  if all systems are dead.

 private boolean allAdSystemsFailed()
 {
  boolean result = true;
  int systemsCount = mSystems.length - 1;
  
  while (systemsCount >= 0 && result)
  {
   result = (result && mSystemStatus[systemsCount].isFailed());
   -- systemsCount;
  }
  
  return result;
 }


Conclusion


 Ok, now the SBCAdSystem is finished. But for now we have no ad networks implemented to choose from yet. Next time we will start with AdMob. During reading you probably imagined thousands of enhancements - like storing the network the user clicks on ads most often. Maintain some ad network preference list on your server and ask for it during construction instead of pure random selection. Enhance the selection taht it will take into account also some priorities you assign to ad networks and so on ... I will be happy to hear about your ideas or code enhancements in comments.