Android Open Source - AdFlake-Client-Android Ad Flake Manager






From Project

Back to project page AdFlake-Client-Android.

License

The source code is released under:

Apache License

If you think the Android project AdFlake-Client-Android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * AdFlakeManager.java (AdFlakeSDK-Android)
 */*w  w w  . ja va  2s . c o m*/
 * Copyright ? 2013 MADE GmbH - All Rights Reserved.
 *
 * Unauthorized copying of this file, via any medium is strictly prohibited
 * unless otherwise noted in the License section of this document header.
 *
 * @file AdFlakeManager.java
 * @copyright 2013 MADE GmbH. All rights reserved.
 * @section License
 * 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.adflake;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Random;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.provider.Settings.Secure;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;

import com.adflake.adapters.AdColonyVideoAdsAdapter;
import com.adflake.obj.Custom;
import com.adflake.obj.Extra;
import com.adflake.obj.Ration;
import com.adflake.util.AdFlakeUtil;

/**
 * The AdFlakeManager class manages the AdFlake configuration. If necessary the
 * class will download it from a remote server.
 */
public class AdFlakeManager
{
  public String adFlakeKey;

  public String localeString;
  public String deviceIDHash;

  public boolean sleeperMode;
  public boolean videoAdsAvailable;

  public Location location;

  /**
   * Instantiates a new ad flake manager.
   * 
   * @param contextReference
   *            the context reference
   * @param adFlakeKey
   *            the ad flake key
   */
  public AdFlakeManager(WeakReference<Context> contextReference, String adFlakeKey)
  {
    Log.i(AdFlakeUtil.ADFLAKE, "Creating adFlakeManager...");
    this._contextReference = contextReference;
    this.adFlakeKey = adFlakeKey;

    this.sleeperMode = false;

    localeString = Locale.getDefault().toString();
    Log.d(AdFlakeUtil.ADFLAKE, "Locale is: " + localeString);

    MessageDigest md;
    try
    {
      md = MessageDigest.getInstance("MD5");
      StringBuffer deviceIDString = new StringBuffer(Secure.ANDROID_ID);
      deviceIDString.append("AdFlake");
      deviceIDHash = AdFlakeUtil.convertToHex(md.digest(deviceIDString.toString().getBytes()));
    }
    catch (NoSuchAlgorithmException e)
    {
      deviceIDHash = "00000000000000000000000000000000";
    }
    Log.d(AdFlakeUtil.ADFLAKE, "Hashed device ID is: " + deviceIDHash);

    Log.i(AdFlakeUtil.ADFLAKE, "Finished creating adFlakeManager");
  }

  /**
   * Sets the config expire timeout.
   * 
   * @param configExpireTimeout
   *            the new config expire timeout
   */
  public static void setConfigExpireTimeout(long configExpireTimeout)
  {
    AdFlakeManager._configExpireTimeout = configExpireTimeout;
  }

  /**
   * Gets the extra.
   * 
   * @return the extra
   */
  public Extra getExtra()
  {
    if (_totalWeight <= 0)
    {
      return null;
    }
    else
    {
      return this._extra;
    }
  }

  /**
   * Gets the darted ration.
   * 
   * @return the darted ration
   */
  public Ration getDartedRation()
  {
    Random random = new Random();

    double r = random.nextDouble() * _totalWeight;
    double s = 0;

    Log.d(AdFlakeUtil.ADFLAKE, "Dart is <" + r + "> of <" + _totalWeight + ">");

    Iterator<Ration> it = this._rationsList.iterator();
    Ration ration = null;
    while (it.hasNext())
    {
      ration = it.next();
      s += ration.weight;

      if (s >= r)
      {
        break;
      }
    }

    return ration;
  }

  /**
   * Gets the ration for current rollover list position.
   * 
   * @return the ration for current rollover list position
   */
  public Ration getRationForCurrentRolloverListPosition()
  {
    if (this._rollovers == null)
    {
      return null;
    }

    Ration ration = null;
    if (this._rollovers.hasNext())
    {
      ration = this._rollovers.next();
    }

    return ration;
  }

  /**
   * Reset rollover list pointer to the beginning of the list.
   */
  public void resetRollover()
  {
    this._rollovers = this._rationsList.iterator();
  }

  /**
   * Fetch a custom banner from server with the specifeid network id.
   * 
   * @param nid
   *            the nid
   * @return the custom
   */
  public Custom fetchCustomBannerFromServerWithNetworkID(String nid)
  {
    HttpClient httpClient = new DefaultHttpClient();

    String locationString;
    if (_extra.locationOn == 1)
    {
      location = getCurrentLocation();
      if (location != null)
      {
        locationString = String.format(AdFlakeUtil.locationString, location.getLatitude(), location.getLongitude(), location.getTime());
      }
      else
      {
        locationString = "";
      }
    }
    else
    {
      location = null;
      locationString = "";
    }

    String url = String.format(AdFlakeUtil.urlCustom, this.adFlakeKey, nid, deviceIDHash, localeString, locationString, AdFlakeUtil.VERSION);
    HttpGet httpGet = new HttpGet(url);

    HttpResponse httpResponse;
    try
    {
      httpResponse = httpClient.execute(httpGet);

      Log.d(AdFlakeUtil.ADFLAKE, httpResponse.getStatusLine().toString());

      HttpEntity entity = httpResponse.getEntity();

      if (entity != null)
      {
        InputStream inputStream = entity.getContent();
        String jsonString = convertStreamToString(inputStream);
        return parseCustomJsonString(jsonString);
      }
    }
    catch (ClientProtocolException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "Caught ClientProtocolException in getCustom()", e);
    }
    catch (IOException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "Caught IOException in getCustom()", e);
    }

    return null;
  }

  /**
   * Fetch the ADFlake config from the remote server.
   * 
   * @note If the config timeout has not been hit, the previously downloaded
   *       config will be reused. If testmode is enabled, the config will
   *       always be downloaded.
   */
  public void fetchConfigFromServer()
  {
    Context context = _contextReference.get();

    // If the context is null here something went wrong with initialization.
    if (context == null)
    {
      return;
    }

    SharedPreferences adFlakePrefs = context.getSharedPreferences(adFlakeKey, Context.MODE_PRIVATE);
    String jsonString = adFlakePrefs.getString(PREFS_STRING_CONFIG, null);
    long timestamp = adFlakePrefs.getLong(PREFS_STRING_TIMESTAMP, -1);

    Log.d(AdFlakeUtil.ADFLAKE, "Prefs{" + adFlakeKey + "}: {\"" + PREFS_STRING_CONFIG + "\": \"" + jsonString + "\", \"" + PREFS_STRING_TIMESTAMP + "\": " + timestamp + "}");

    if (jsonString == null || _configExpireTimeout == -1 || System.currentTimeMillis() >= timestamp + _configExpireTimeout || AdFlakeTargeting.getTestMode() == true)
    {
      Log.i(AdFlakeUtil.ADFLAKE, "Stored config info not present or expired, fetching fresh data");

      HttpClient httpClient = new DefaultHttpClient();

      String url = String.format(AdFlakeUtil.urlConfig, this.adFlakeKey, AdFlakeUtil.VERSION);
      HttpGet httpGet = new HttpGet(url);

      HttpResponse httpResponse;
      try
      {
        httpResponse = httpClient.execute(httpGet);

        Log.d(AdFlakeUtil.ADFLAKE, httpResponse.getStatusLine().toString());

        HttpEntity entity = httpResponse.getEntity();

        if (entity != null)
        {
          InputStream inputStream = entity.getContent();
          jsonString = convertStreamToString(inputStream);

          SharedPreferences.Editor editor = adFlakePrefs.edit();
          editor.putString(PREFS_STRING_CONFIG, jsonString);
          editor.putLong(PREFS_STRING_TIMESTAMP, System.currentTimeMillis());
          editor.commit();
        }
      }
      catch (ClientProtocolException e)
      {
        Log.e(AdFlakeUtil.ADFLAKE, "Caught ClientProtocolException in fetchConfig()", e);
      }
      catch (IOException e)
      {
        Log.e(AdFlakeUtil.ADFLAKE, "Caught IOException in fetchConfig()", e);
      }
    }
    else
    {
      Log.i(AdFlakeUtil.ADFLAKE, "Using stored config data");
    }

    parseConfigurationString(jsonString);
  }

  /**
   * Convert stream to string.
   * 
   * @param is
   *            the is
   * @return the string
   */
  private String convertStreamToString(InputStream is)
  {
    BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8192);
    StringBuilder sb = new StringBuilder();

    String line = null;
    try
    {
      while ((line = reader.readLine()) != null)
      {
        sb.append(line + "\n");
      }
    }
    catch (IOException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "Caught IOException in convertStreamToString()", e);
      return null;
    }
    finally
    {
      try
      {
        is.close();
      }
      catch (IOException e)
      {
        Log.e(AdFlakeUtil.ADFLAKE, "Caught IOException in convertStreamToString()", e);
        return null;
      }
    }

    return sb.toString();
  }

  /**
   * Parses the configuration section from the specified JSON string.
   * 
   * @param jsonString
   *            the json string
   */
  private void parseConfigurationString(String jsonString)
  {
    Log.d(AdFlakeUtil.ADFLAKE, "Received jsonString: " + jsonString);

    try
    {
      JSONObject json = new JSONObject(jsonString);

      parseExtraJson(json.getJSONObject("extra"));
      parseRationsJson(json.getJSONArray("rations"));
      parseVideoRationsJson(json.getJSONArray("videoRations"));
    }
    catch (JSONException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "Unable to parse response from JSON. This may or may not be fatal.", e);
      this._extra = new Extra();
    }
    catch (NullPointerException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "Unable to parse response from JSON. This may or may not be fatal.", e);
      this._extra = new Extra();
    }
  }

  /**
   * Parses the extra section from the specified json object.
   * 
   * @param json
   *            the json
   */
  private void parseExtraJson(JSONObject json)
  {
    Extra extra = new Extra();

    try
    {
      extra.cycleTime = json.getInt("cycle_time");
      extra.locationOn = json.getInt("location_on");
      extra.transition = json.getInt("transition");

      // Due to legacy clients, the server reports alpha on a scale of
      // 0.0-1.0
      // instead of 0-255

      JSONObject backgroundColor = json.getJSONObject("background_color_rgb");
      extra.bgRed = backgroundColor.getInt("red");
      extra.bgGreen = backgroundColor.getInt("green");
      extra.bgBlue = backgroundColor.getInt("blue");
      extra.bgAlpha = backgroundColor.getInt("alpha") * 255;

      JSONObject textColor = json.getJSONObject("text_color_rgb");
      extra.fgRed = textColor.getInt("red");
      extra.fgGreen = textColor.getInt("green");
      extra.fgBlue = textColor.getInt("blue");
      extra.fgAlpha = textColor.getInt("alpha") * 255;
    }
    catch (JSONException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "Exception in parsing config.extra JSON. This may or may not be fatal.", e);
    }

    this._extra = extra;
  }

  /**
   * Parses the rations section from the specified json object.
   * 
   * @param json
   *            the json
   */
  private void parseRationsJson(JSONArray json)
  {
    List<Ration> rationsList = new ArrayList<Ration>();

    this._totalWeight = 0;

    try
    {
      int i;
      for (i = 0; i < json.length(); i++)
      {
        JSONObject jsonRation = json.getJSONObject(i);
        if (jsonRation == null)
        {
          continue;
        }

        Ration ration = new Ration();

        ration.nid = jsonRation.getString("nid");
        ration.type = jsonRation.getInt("type");
        ration.name = jsonRation.getString("nname");
        ration.weight = jsonRation.getInt("weight");
        ration.priority = jsonRation.getInt("priority");

        // Quattro has a special key format due to legacy compatibility.
        switch (ration.type)
        {
          case AdFlakeUtil.NETWORK_TYPE_QUATTRO:
            JSONObject keyObj = jsonRation.getJSONObject("key");
            ration.key = keyObj.getString("siteID");
            ration.key2 = keyObj.getString("publisherID");
            break;

          case AdFlakeUtil.NETWORK_TYPE_NEXAGE:
            keyObj = jsonRation.getJSONObject("key");
            ration.key = keyObj.getString("dcn");
            ration.key2 = keyObj.getString("position");
            break;

          default:
            ration.key = jsonRation.getString("key");
            break;
        }

        this._totalWeight += ration.weight;

        rationsList.add(ration);
      }
    }
    catch (JSONException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "JSONException in parsing config.rations JSON. This may or may not be fatal.", e);
    }

    Collections.sort(rationsList);

    if (this._totalWeight <= 0)
    {
      Log.i(AdFlakeUtil.ADFLAKE, "Sum of ration weights is 0 - no ads to be shown, sleeper mode enabled");
      this.sleeperMode = true;
    }
    else
    {
      this.sleeperMode = false;
    }

    this._rationsList = rationsList;
    this._rollovers = this._rationsList.iterator();
  }

  /**
   * Parses the rations section from the specified json object.
   * 
   * @param json
   *            the json
   */
  private void parseVideoRationsJson(JSONArray json)
  {
    List<Ration> rationsList = new ArrayList<Ration>();

    _totalVideoWeight = 0;

    try
    {
      int i;
      for (i = 0; i < json.length(); i++)
      {
        JSONObject jsonRation = json.getJSONObject(i);
        if (jsonRation == null)
        {
          continue;
        }

        Ration ration = new Ration();

        ration.nid = jsonRation.getString("nid");
        ration.type = jsonRation.getInt("type");
        ration.name = jsonRation.getString("nname");
        ration.weight = jsonRation.getInt("weight");
        ration.priority = jsonRation.getInt("priority");

        switch (ration.type)
        {
          case AdFlakeUtil.NETWORK_TYPE_BEACHFRONT:
          case AdFlakeUtil.NETWORK_TYPE_ADCOLONY:
            ration.key = jsonRation.getString("key");

            int zoneIndex = ration.key.indexOf("|;|");
            if (zoneIndex < 0)
            {
              Log.w(AdFlakeUtil.ADFLAKE, "key separator not found for network=" + ration.name);
              continue;
            }

            ration.key2 = ration.key.substring(zoneIndex + 3);
            ration.key = ration.key.substring(0, zoneIndex);
            break;

          default:
            ration.key = jsonRation.getString("key");
            break;
        }

        this._totalVideoWeight += ration.weight;

        rationsList.add(ration);
      }
    }
    catch (JSONException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "JSONException in parsing config.rations JSON. This may or may not be fatal.", e);
    }

    Collections.sort(rationsList);

    if (_totalVideoWeight <= 0)
    {
      Log.i(AdFlakeUtil.ADFLAKE, "Sum of video ration weights is 0 - no video ads available");
      this.videoAdsAvailable = false;
    }
    else
    {
      this.videoAdsAvailable = true;
    }

    this._videoRationsList = rationsList;
  }

  /**
   * Parses the custom section from the specified json string.
   * 
   * @param jsonString
   *            the json string
   * @return the custom
   */
  private Custom parseCustomJsonString(String jsonString)
  {
    Log.d(AdFlakeUtil.ADFLAKE, "Received custom jsonString: " + jsonString);

    Custom custom = new Custom();
    try
    {
      JSONObject json = new JSONObject(jsonString);

      custom.type = json.getInt("ad_type");
      custom.imageLink = json.getString("img_url");
      custom.link = json.getString("redirect_url");
      custom.description = json.getString("ad_text");

      try
      {
        custom.imageLink640x100 = json.getString("img_url_640x100");
      }
      catch (JSONException e)
      {
        custom.imageLink640x100 = null;
      }
      try
      {
        custom.imageLink480x75 = json.getString("img_url_480x75");
      }
      catch (JSONException e)
      {
        custom.imageLink480x75 = null;
      }

      DisplayMetrics metrics = new DisplayMetrics();
      ((WindowManager) _contextReference.get().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);

      if (metrics.density >= 2.0 && custom.type == AdFlakeUtil.CUSTOM_TYPE_BANNER && custom.imageLink640x100 != null && custom.imageLink640x100.length() != 0)
      {
        custom.image = fetchImageWithURL(custom.imageLink640x100);
      }
      else if (metrics.density >= 1.5 && custom.type == AdFlakeUtil.CUSTOM_TYPE_BANNER && custom.imageLink480x75 != null && custom.imageLink480x75.length() != 0)
      {
        custom.image = fetchImageWithURL(custom.imageLink480x75);
      }
      else
      {
        custom.image = fetchImageWithURL(custom.imageLink);
      }
    }
    catch (JSONException e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "Caught JSONException in parseCustomJsonString()", e);
      return null;
    }

    return custom;
  }

  /**
   * Fetch image with the specified url.
   * 
   * @param urlString
   *            the url string
   * @return the drawable
   */
  private Drawable fetchImageWithURL(String urlString)
  {
    try
    {
      URL url = new URL(urlString);
      InputStream is = (InputStream) url.getContent();
      Drawable d = Drawable.createFromStream(is, "src");
      return d;
    }
    catch (Exception e)
    {
      Log.e(AdFlakeUtil.ADFLAKE, "Unable to fetchImage(): ", e);
      return null;
    }
  }

  /**
   * Gets the current location.
   * 
   * @note If location is not enabled, this method will return null
   * @return the current location or null if location access is not enabled or
   *         granted by the user.
   */
  public Location getCurrentLocation()
  {
    if (_contextReference == null)
    {
      return null;
    }

    Context context = _contextReference.get();
    if (context == null)
    {
      return null;
    }

    Location location = null;

    if (context.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
    {
      LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
      location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    }
    else if (context.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
    {
      LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
      location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
    }
    return location;
  }

  public Ration getNextDartedVideoRation(List<Ration> usedVideoRations)
  {
    Random random = new Random();

    double actualWeight = 0;

    for (Ration ration : _videoRationsList)
    {
      if (usedVideoRations.contains(ration))
        continue;

      actualWeight += ration.weight;
    }

    double r = random.nextDouble() * actualWeight;
    double s = 0;

    Log.d(AdFlakeUtil.ADFLAKE, "Dart is <" + r + "> of <" + actualWeight + "> and total <" + _totalWeight + ">");

    Iterator<Ration> it = this._videoRationsList.iterator();
    Ration ration = null;
    while (it.hasNext())
    {
      ration = it.next();

      if (usedVideoRations.contains(ration))
        continue;

      s += ration.weight;

      if (s >= r)
      {
        break;
      }
    }

    return ration;
  }

  public int getVideoRationCount()
  {
    return _videoRationsList.size();
  }

  public void prepareVideoAdaptersForLayout(AdFlakeLayout adFlakeLayout)
  {
    Log.d(AdFlakeUtil.ADFLAKE, "prepareVideoAdaptersForLayout");
    
    for (Ration ration : _videoRationsList)
    {
      try
      {
        switch (ration.type)
        {
          case AdFlakeUtil.NETWORK_TYPE_ADCOLONY:
            AdColonyVideoAdsAdapter.prepareForRation(ration, adFlakeLayout);
            break;

          default:
            break;
        }
      }
      catch (Throwable ex)
      {
        Log.e(AdFlakeUtil.ADFLAKE, "prepareVideoAdaptersForLayout failed to prepare for ration=" + ration.name + "\n error=" + ex.toString());
      }
    }
  }

  private Extra _extra;
  private List<Ration> _rationsList;
  private List<Ration> _videoRationsList;
  private double _totalWeight = 0;
  private double _totalVideoWeight = 0;
  private WeakReference<Context> _contextReference;

  private Iterator<Ration> _rollovers;

  /** Default config expire timeout is 30 minutes. */
  private static long _configExpireTimeout = 1800000;

  private final static String PREFS_STRING_TIMESTAMP = "timestamp";
  private final static String PREFS_STRING_CONFIG = "config";
}




Java Source Code List

com.adflake.AdFlakeLayout.java
com.adflake.AdFlakeManager.java
com.adflake.AdFlakeTargeting.java
com.adflake.adapters.AdColonyVideoAdsAdapter.java
com.adflake.adapters.AdFlakeAdapter.java
com.adflake.adapters.AmazonAdsAdapter.java
com.adflake.adapters.AppBrainAppLiftAdapter.java
com.adflake.adapters.BeachfrontVideoAdsAdapter.java
com.adflake.adapters.CustomAdapter.java
com.adflake.adapters.EventAdapter.java
com.adflake.adapters.GenericAdapter.java
com.adflake.adapters.GoogleAdMobAdsAdapter.java
com.adflake.adapters.GoogleAdMobVideoAdsAdapter.java
com.adflake.adapters.GreystripeAdapter.java
com.adflake.adapters.InMobiAdapter.java
com.adflake.adapters.JumptapAdapter.java
com.adflake.adapters.KomliMobileAdAdapter.java
com.adflake.adapters.LeadBoltAdapter.java
com.adflake.adapters.MdotMAdapter.java
com.adflake.adapters.MillennialAdapter.java
com.adflake.adapters.MobClixAdapter.java
com.adflake.adapters.MobFoxAdapter.java
com.adflake.adapters.TodacellAdapter.java
com.adflake.obj.Custom.java
com.adflake.obj.Extra.java
com.adflake.obj.Ration.java
com.adflake.sampleapp.SampleActivity.java
com.adflake.util.AdFlakeUtil.java