Android Open Source - plus1-android-sdk Plus1 Banner Asker






From Project

Back to project page plus1-android-sdk.

License

The source code is released under:

Copyright (c) 2012, WapStart All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Red...

If you think the Android project plus1-android-sdk 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

/**
 * Copyright (c) 2011, Alexander Klestov <a.klestov@co.wapstart.ru>
 * All rights reserved./*  w ww  . jav a 2s.com*/
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *   * Neither the name of the "Wapstart" nor the names
 *     of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package ru.wapstart.plus1.sdk;

import android.content.Context;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.webkit.WebView;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import ru.wapstart.plus1.sdk.BaseRequestLoader.ChangeSdkPropertiesListener;
import ru.wapstart.plus1.sdk.BaseRequestLoader.SdkAction;
import ru.wapstart.plus1.sdk.BaseRequestLoader.SdkParameter;
import ru.wapstart.plus1.sdk.InitRequestLoader.InitRequestLoadListener;
import ru.wapstart.plus1.sdk.Plus1BannerDownloadListener.BannerAdType;
import ru.wapstart.plus1.sdk.Plus1BannerDownloadListener.LoadError;

public class Plus1BannerAsker {
  public final class CallbackUrlNotDefinedException extends RuntimeException {
    private CallbackUrlNotDefinedException(String detailMessage) {
      super(detailMessage);
    }
  }

  private static final String LOGTAG = "Plus1BannerAsker";
  private static final String VALUE_OPEN_IN_BROWSER = "browser";
  private static final String VALUE_OPEN_IN_APPLICATION = "application";
  private static final String VALUE_CANCEL = "-1";
  private static final String TASK_LOCK_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
  private static final int TASK_LOCK_TIME_DEFAULT = 3600; // 1 hour
  private static final int TASK_LOCK_TIME_WEEK = 604800; // 7 days

  private Plus1Request mRequest              = null;
  private Plus1BannerView mView              = null;
  private HtmlBannerDownloader mDownloaderTask      = null;

  private boolean mDisabledAutoDetectLocation        = false;
  private boolean mRemoveBannersOnPause          = false;
  private boolean mDisabledWebViewCorePausing        = false;

  private int mRefreshDelay      = Constants.DEFAULTS_BANNER_REFRESH_INTERVAL;
  private int mLocationRefreshDelay  = Constants.DEFAULTS_LOCATION_REFRESH_INTERVAL;
  private int mRefreshRetryNum    = Constants.DEFAULTS_REFRESH_RETRY_NUM;
  private int mReInitDelay      = Constants.DEFAULTS_REINIT_INTERVAL;
  private int mFacebookInfoDelay    = Constants.DEFAULTS_FACEBOOK_INFO_REFRESH_INTERVAL;
  private int mTwitterInfoDelay    = Constants.DEFAULTS_FACEBOOK_INFO_REFRESH_INTERVAL;

  private boolean mInitialized              = false;
  private boolean mLocationRequestUpdatesEnabled      = false;
  private boolean mWebViewCorePaused            = false;
  private int mRefreshRetryCount              = 0;

  private String mCallbackUrl                = null;

  private LocationManager mLocationManager        = null;
  private LocationListener mLocationListener        = null;

  private Plus1BannerDownloadListener mDownloadListener  = null;

  private EnumMap<SdkParameter, String> mBackupParameterMap =
    new EnumMap<SdkParameter, String>(SdkParameter.class);

  private static enum InnerTask {reinitTask, advertisingIdTask, facebookInfoTask, twitterInfoTask};

  Runnable mExecuteDownloadTask = new Runnable() {
    public void run() {
      if (!(mView.isClosed() || mView.isExpanded())) {
        mDownloaderTask = makeDownloaderTask();
        mDownloaderTask.execute(mRequest);
      }

      if (isAutoRefreshEnabled())
        mExecuteDownloadHandler.postDelayed(this, mRefreshDelay * 1000);
    }
  };
  private Handler mExecuteDownloadHandler          = new Handler();

  private Runnable mReinitRequestTask = new Runnable() {
    public void run() {
      makeInitRequestTask().execute(mRequest);

      if (!hasLockForTask(InnerTask.reinitTask))
        mReinitHandler.postDelayed(this, mReInitDelay * 1000);
    }
  };
  private Handler mReinitHandler = new Handler();

  final private Runnable mFacebookInfoTask = new Runnable() {
    public void run() {
      try {
        final Class sessionCls = Class.forName("com.facebook.Session");
        final Class userCls = Class.forName("com.facebook.model.GraphUser");
        final Class requestCls = Class.forName("com.facebook.Request");
        final Class callbackCls = Class.forName("com.facebook.Request$GraphUserCallback");

        final Object session = sessionCls.getMethod("getActiveSession").invoke(null);

        if (session != null && (Boolean)sessionCls.getMethod("isOpened").invoke(session) == true) {
          final Object callbackInstance = Proxy.newProxyInstance(callbackCls.getClassLoader(), new Class[]{callbackCls}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              if(method.getName().equals("onCompleted")) {
                if (session == sessionCls.getMethod("getActiveSession").invoke(null) && args[0] != null) {
                  mRequest.setFacebookUserHash(
                    Plus1Helper.getHash(
                      String.valueOf(
                        userCls.getMethod("getId").invoke(args[0])
                      )
                    )
                  );

                  Plus1Helper.setStorageValue(
                    mView.getContext(),
                    Constants.PREFERENCES_KEY_FACEBOOK_USER_ID,
                    mRequest.getFacebookUserHash()
                  );

                  Log.d(LOGTAG, "Facebook user hash was updated: " + mRequest.getFacebookUserHash());

                  mFacebookInfoHandler.removeCallbacks(mFacebookInfoTask);
                  setLockForTask(InnerTask.facebookInfoTask, TASK_LOCK_TIME_DEFAULT);
                }

                return 1;
              }

              return -1;
            }
          });

          requestCls.getMethod("executeMeRequestAsync", sessionCls, callbackCls)
            .invoke(null, session, callbackInstance);
        }

        if (!hasLockForTask(InnerTask.facebookInfoTask))
          mFacebookInfoHandler.postDelayed(this, mFacebookInfoDelay * 1000);
      } catch (ClassNotFoundException e) {
        Log.d(LOGTAG, "Application is not using facebook sdk");
        setLockForTask(InnerTask.facebookInfoTask, TASK_LOCK_TIME_WEEK);
      } catch (Exception e) {
        Log.w(LOGTAG, "Some error occurred while using facebook sdk", e);
      }
    }
  };
  private Handler mFacebookInfoHandler = new Handler();

  final private Runnable mTwitterInfoTask = new Runnable() {
    public void run() {
      try {
        final Class factoryCls = Class.forName("twitter4j.TwitterFactory");
        final Class twitterCls = Class.forName("twitter4j.TwitterImpl");
        final Class configCls = Class.forName("twitter4j.conf.Configuration");

        // TODO: search another way to get configuration
        Field hackedMap = twitterCls.getDeclaredField("implicitParamsMap");
        hackedMap.setAccessible(true);
        HashMap hashMap = new HashMap();
        hashMap.putAll((Map)hackedMap.get(null));

        for (Object conf : hashMap.keySet()) {
          boolean allowAuth =
            configCls.getMethod("getOAuthConsumerKey").invoke(conf) != null
            && configCls.getMethod("getOAuthConsumerSecret").invoke(conf) != null;

          if (allowAuth) {
            if ((Boolean)configCls.getMethod("isApplicationOnlyAuthEnabled").invoke(conf)) {
              allowAuth =
                configCls.getMethod("getOAuth2TokenType").invoke(conf) != null
                && configCls.getMethod("getOAuth2AccessToken").invoke(conf) != null;
            } else {
              allowAuth =
                configCls.getMethod("getOAuthAccessToken").invoke(conf) != null
                && configCls.getMethod("getOAuthAccessTokenSecret").invoke(conf) != null;
            }
          } else {
            allowAuth =
              configCls.getMethod("getUser").invoke(conf) != null
              && configCls.getMethod("getPassword").invoke(conf) != null;
          }

          if (allowAuth) {
            Object twitter = factoryCls.getMethod("getInstance").invoke(
              factoryCls.getConstructor(configCls).newInstance(conf)
            );

            mRequest.setTwitterUserHash(
              Plus1Helper.getHash(
                String.valueOf(
                  twitterCls.getMethod("getId").invoke(twitter)
                )
              )
            );

            Plus1Helper.setStorageValue(
              mView.getContext(),
              Constants.PREFERENCES_KEY_TWITTER_USER_ID,
              mRequest.getTwitterUserHash()
            );

            Log.d(LOGTAG, "Twitter user hash was updated: " + mRequest.getTwitterUserHash());

            setLockForTask(InnerTask.twitterInfoTask, TASK_LOCK_TIME_DEFAULT);
            return;
          }
        }

        if (!hasLockForTask(InnerTask.twitterInfoTask))
          mTwitterInfoHandler.postDelayed(this, mTwitterInfoDelay * 1000);
      } catch (ClassNotFoundException e) {
        Log.d(LOGTAG, "Application is not using twitter4j sdk");
        setLockForTask(InnerTask.twitterInfoTask, TASK_LOCK_TIME_WEEK);
      } catch (Exception e) {
        Log.w(LOGTAG, "Some error occurred while using twitter4j sdk", e);
      }
    }
  };
  private Handler mTwitterInfoHandler = new Handler();

  public static Plus1BannerAsker create(
    Plus1Request request, Plus1BannerView view
  ) {
    return new Plus1BannerAsker(request, view);
  }

  public void asyncFetchAdvertisingInfo(final Context context) {
    try {
      final Class adIdClientCls = Class.forName("com.google.android.gms.ads.identifier.AdvertisingIdClient");
      final Class adIdClientInfoCls = Class.forName("com.google.android.gms.ads.identifier.AdvertisingIdClient$Info");

      new Thread(new Runnable() {
        @Override
        public void run() {
          try {
            Object adInfo =
              adIdClientCls.getMethod("getAdvertisingIdInfo", Context.class)
                .invoke(null, context);

            if (adInfo != null) {
              mRequest.setAdvertisingId(
                (String)adIdClientInfoCls.getMethod("getId").invoke(adInfo)
              );
              mRequest.setLimitAdTrackingEnabled(
                (Boolean)adIdClientInfoCls.getMethod("isLimitAdTrackingEnabled").invoke(adInfo)
              );

              Plus1Helper.setStorageValue(
                mView.getContext(),
                Constants.PREFERENCES_KEY_ADVERTISING_ID,
                mRequest.getAdvertisingId()
              );
              Plus1Helper.setStorageBooleanValue(
                mView.getContext(),
                Constants.PREFERENCES_KEY_LIMIT_AD_TRACKING_ENABLED,
                mRequest.isLimitAdTrackingEnabled()
              );

              Log.d(LOGTAG, "Google Advertising Id: " + mRequest.getAdvertisingId());
              Log.d(LOGTAG, "Limit Ad Tracking is " + (mRequest.isLimitAdTrackingEnabled() ? "ENABLED" : "DISABLED"));

              setLockForTask(InnerTask.advertisingIdTask, TASK_LOCK_TIME_DEFAULT);
            }
          } catch (Exception e) {
            Log.d(LOGTAG, "Unable to obtain AdvertisingIdClient.getAdvertisingIdInfo() (Google Play Services is not available)");
            setLockForTask(InnerTask.advertisingIdTask, TASK_LOCK_TIME_WEEK);
          }
        }
      }).start();
    } catch (ClassNotFoundException e) {
      Log.d(LOGTAG, "Application is not using Google Play Services sdk");
      setLockForTask(InnerTask.advertisingIdTask, TASK_LOCK_TIME_WEEK);
    }
  }

  public Plus1BannerAsker(Plus1Request request, Plus1BannerView view) {
    mRequest = request;
    mView = view;
  }

  public void onPause() {
    stop();

    mReinitHandler.removeCallbacks(mReinitRequestTask);
    mFacebookInfoHandler.removeCallbacks(mFacebookInfoTask);
    mTwitterInfoHandler.removeCallbacks(mTwitterInfoTask);

    if (!isDisabledAutoDetectLocation())
      removeLocationUpdates();

    if (isRemoveBannersOnPause())
      mView.removeAllBanners();
    else
      mView.onPause();

    if (!isDisabledWebViewCorePausing() && !mWebViewCorePaused) {
      try{
        new WebView(mView.getContext()).pauseTimers();
        Log.d(LOGTAG, "WebView core thread was PAUSED");

        mWebViewCorePaused = true;
      }catch(OutOfMemoryError ex){
        ex.printStackTrace();
      }
    }
  }

  public void onResume() {
    init();

    if (!mView.isExpanded())
      start();

    if (!isDisabledAutoDetectLocation())
      requestLocationUpdates(false); // NOTE: include disabled providers

    mView.onResume();

    if (!hasLockForTask(InnerTask.advertisingIdTask))
      asyncFetchAdvertisingInfo(mView.getContext());
    if (!hasLockForTask(InnerTask.facebookInfoTask))
      mFacebookInfoHandler.post(mFacebookInfoTask);
    if (!hasLockForTask(InnerTask.twitterInfoTask))
      mTwitterInfoHandler.post(mTwitterInfoTask);

    if (mWebViewCorePaused) {
      try{
        new WebView(mView.getContext()).resumeTimers();
        Log.d(LOGTAG, "WebView core thread was RESUMED");

        mWebViewCorePaused = false;
      }catch(OutOfMemoryError ex){
        ex.printStackTrace();
      }
    }
  }

  public boolean isDisabledAutoDetectLocation() {
    return mDisabledAutoDetectLocation;
  }

  public Plus1BannerAsker disableAutoDetectLocation() {
    mDisabledAutoDetectLocation = true;

    return this;
  }

  public boolean isRemoveBannersOnPause() {
    return mRemoveBannersOnPause;
  }

  public Plus1BannerAsker setRemoveBannersOnPause(boolean orly) {
    mRemoveBannersOnPause = orly;

    return this;
  }

  public boolean isDisabledWebViewCorePausing() {
    return mDisabledWebViewCorePausing;
  }

  /**
   * NOTE: This method is useful when you are using WebView instances
   *        in another activities of your application. Please note, when
   *        WebView core thread is running, all banners of activity still
   *        working in background. The important thing is whether they are
   *        consuming CPU cycles. To reduce this effect, please remove all
   *        banners when you pausing activity. Use setRemoveBannersOnPause()
   *        method to remove them automatically on pausing asker.
   * @see setRemoveBannersOnPause() method
   */
  public Plus1BannerAsker setDisabledWebViewCorePausing(boolean orly) {
    mDisabledWebViewCorePausing = orly;

    return this;
  }

  public Plus1BannerAsker setRefreshDelay(int delayInSeconds) {
    mRefreshDelay = delayInSeconds;

    return this;
  }

  public Plus1BannerAsker setRefreshRetryNum(int refreshRetryNum) {
    mRefreshRetryNum = refreshRetryNum;

    return this;
  }

  public Plus1BannerAsker setReInitDelay(int delayInSeconds) {
    mReInitDelay = delayInSeconds;

    return this;
  }

  public Plus1BannerAsker setLocationRefreshDelay(int delayInSeconds) {
    mLocationRefreshDelay = delayInSeconds;

    if (!isDisabledAutoDetectLocation() && mLocationRequestUpdatesEnabled) {
      removeLocationUpdates();
      requestLocationUpdates(false);
    }

    return this;
  }

  public Plus1BannerAsker setCallbackUrl(String callbackUrl) {
    mCallbackUrl = callbackUrl;

    return this;
  }

  public boolean isAutoRefreshEnabled() {
    return mRefreshDelay > 0;
  }

  public boolean isLocationAutoRefreshEnabled() {
    return mLocationRefreshDelay > 0;
  }

  public Plus1BannerAsker setDownloadListener(
    Plus1BannerDownloadListener downloadListener
  ) {
    mDownloadListener = downloadListener;

    return this;
  }

  public Plus1BannerAsker init() {
    if (mInitialized)
      return this;

    if (!mRequest.isDisabledOpenLinkAction() && mCallbackUrl == null)
      throw new CallbackUrlNotDefinedException("You must define callback url");

    if (!hasLockForTask(InnerTask.reinitTask))
      mReinitHandler.post(mReinitRequestTask);

    if (!isDisabledAutoDetectLocation()) {
      mLocationManager =
        (LocationManager)mView.getContext().getSystemService(
          Context.LOCATION_SERVICE
        );

      mLocationListener = new LocationListener() {
        public void onLocationChanged(Location location) {
          mRequest.setLocation(location);

          if (!isLocationAutoRefreshEnabled())
            removeLocationUpdates();
        }

        public void onProviderDisabled(String provider) {
          Log.d(LOGTAG, "Location provider '"+provider+"' is disabled");
          requestLocationUpdates();
        }

        public void onProviderEnabled(String provider) {
          Log.d(LOGTAG, "Location provider '"+provider+"' is enabled");
          // NOTE: discard another providers, detect new best provider
          removeLocationUpdates();
          requestLocationUpdates();
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
          Log.d(LOGTAG, "Location provider '"+provider+"' new status: "+status);

          switch (status) {
            case LocationProvider.AVAILABLE:
              removeLocationUpdates();
            case LocationProvider.OUT_OF_SERVICE:
              requestLocationUpdates();
              break;
            case LocationProvider.TEMPORARILY_UNAVAILABLE:
              break;
            default:
              Log.w(
                LOGTAG,
                "Illegal status value of location provider '"
                +provider+"' was found: "+status
              );
          }
        }
      };
    }

    mView
      .addListener(new Plus1BannerView.OnCloseButtonListener() {
        public void onCloseButton(Plus1BannerView view) {
          stop();
        }
      })
      .addListener(new Plus1BannerView.OnExpandListener() {
        public void onExpand(Plus1BannerView view) {
          stop();
        }
      })
      .addListener(new Plus1BannerView.OnCollapseListener() {
        public void onCollapse(Plus1BannerView view) {
          start();
        }
      });

    mRequest
      .setUid(
        Plus1Helper.getStorageValue(
          mView.getContext(),
          Constants.PREFERENCES_KEY_UID
        )
      )
      .setAdvertisingId(
        Plus1Helper.getStorageValue(
          mView.getContext(),
          Constants.PREFERENCES_KEY_ADVERTISING_ID
        )
      )
      .setLimitAdTrackingEnabled(
        Plus1Helper.getStorageBooleanValue(
          mView.getContext(),
          Constants.PREFERENCES_KEY_LIMIT_AD_TRACKING_ENABLED
        )
      )
      .setFacebookUserHash(
        Plus1Helper.getStorageValue(
          mView.getContext(),
          Constants.PREFERENCES_KEY_FACEBOOK_USER_ID
        )
      )
      .setTwitterUserHash(
        Plus1Helper.getStorageValue(
          mView.getContext(),
          Constants.PREFERENCES_KEY_TWITTER_USER_ID
        )
      )
      .setAndroidId(
        Plus1Helper.getAndroidId(mView.getContext())
      )
      .setBuildSerial(
        Plus1Helper.getBuildSerial()
      )
      .setPreferredLocale(
        Locale.getDefault().getDisplayName(Locale.US)
      )
      .setDisplayMetrics(
        Plus1Helper.getDisplayMetrics(mView.getContext())
      )
      .setDisplayOrientation(
        Plus1Helper.getDisplayOrientation(mView.getContext())
      )
      .setContainerMetrics(
        Plus1Helper.getContainerMetrics(mView)
      );

    // NOTE: useful in case when timers are paused and activity was destroyed
    new WebView(mView.getContext()).resumeTimers();

    mInitialized = true;

    return this;
  }

  // NOTE: for manual refreshing
  public void refreshBanner() {
    if (!mView.isExpanded()) {
      stop();
      start();
    } else
      Log.w(LOGTAG, "Banner view is expanded, so refresh was prevented");

    Log.d(LOGTAG, "TEST: " + mView.getContext().getResources().getConfiguration().orientation);
  }

  private void start() {
    Log.d(LOGTAG, "start() method fired");

    if (mRequest == null || mView == null || mDownloaderTask != null)
      return;

    mExecuteDownloadHandler.post(mExecuteDownloadTask);
  }

  private void stop() {
    Log.d(LOGTAG, "stop() method fired");

    if (mDownloaderTask != null) {
      mDownloaderTask.cancel(true);
      mDownloaderTask = null;
    }

    mExecuteDownloadHandler.removeCallbacks(mExecuteDownloadTask);
  }

  private void requestLocationUpdates() {
    requestLocationUpdates(true);
  }

  private void requestLocationUpdates(boolean enabledProviderOnly) {
    Criteria criteria = new Criteria();

    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    criteria.setCostAllowed(false);

    String provider =
      mLocationManager.getBestProvider(criteria, enabledProviderOnly);

    if (provider == null) {
      Log.i(LOGTAG, "Location provider is not found, updates turned off");
      return;
    }

    try {
      mLocationManager.requestLocationUpdates(
        provider,
        mLocationRefreshDelay * 1000,
        500f,
        mLocationListener
      );

      mLocationRequestUpdatesEnabled = true;

      if (mRequest.getLocation() == null) {
        mRequest.setLocation(
          mLocationManager.getLastKnownLocation(provider)
        );
      }

      Log.d(
        LOGTAG,
        "Location provider '"+provider+"' was choosen for updates"
      );
    } catch (IllegalArgumentException e) {
      if (!enabledProviderOnly) {
        Log.d(LOGTAG, "Location provider '"+provider+"' doesn't exist - request enabled only providers");
        requestLocationUpdates(true);
      } else
        Log.i(LOGTAG, "Location provider '"+provider+"' doesn't exist on this device, updates turned off");
    }
  }

  private void removeLocationUpdates() {
    if (mLocationRequestUpdatesEnabled) {
      mLocationManager.removeUpdates(mLocationListener);

      mLocationRequestUpdatesEnabled = false;
    }
  }

  private HtmlBannerDownloader makeDownloaderTask()
  {
    mRefreshRetryCount = 0;

    HtmlBannerDownloader task = new HtmlBannerDownloader();
    task.addDownloadListener(new Plus1BannerDownloadListener() {
      public void onBannerLoaded(String content, BannerAdType adType) {
        mRefreshRetryCount = 0;

        mView.loadAd(content, adType);
      }

      public void onBannerLoadFailed(LoadError error) {
        if (++mRefreshRetryCount >= mRefreshRetryNum)
          stop();
      }
    });

    if (mDownloadListener != null)
      task.addDownloadListener(mDownloadListener);

    modifyRequestLoaderTask(task);

    return task;
  }

  private InitRequestLoader makeInitRequestTask()
  {
    InitRequestLoader task = new InitRequestLoader();
    task.addInitRequestLoadListener(new InitRequestLoadListener() {
      public void onUniqueIdLoaded(String uid) {
        Plus1Helper.setStorageValue(
          mView.getContext(),
          Constants.PREFERENCES_KEY_UID,
          uid
        );

        mRequest.setUid(uid);
        Log.w(LOGTAG, "UID was updated by init request: " + uid);

        setLockForTask(InnerTask.reinitTask, TASK_LOCK_TIME_DEFAULT);
      }

      public void onUniqueIdLoadFailed() {
        Log.w(LOGTAG, "Failed to load UID by init request");
      }
    });

    modifyRequestLoaderTask(task);

    return task;
  }

  private void modifyRequestLoaderTask(BaseRequestLoader task) {
    task.addChangeSdkPropertiesListener(new ChangeSdkPropertiesListener() {
      public void onSdkParametersLoaded(EnumMap<SdkParameter, String> parameters) {
        for(Entry<SdkParameter, String> entry : parameters.entrySet()) {
          SdkParameter key = entry.getKey();
          String value = entry.getValue();
          String prevValue = null;
          boolean cancelLogic = value.equals(VALUE_CANCEL);

          if (cancelLogic) {
            if (!mBackupParameterMap.containsKey(key))
              continue;

            value = mBackupParameterMap.get(key);
            mBackupParameterMap.remove(key);
          }

          switch (key) {
            case refreshDelay:
              prevValue = String.valueOf(mRefreshDelay);
              mRefreshDelay = Integer.parseInt(value);
              break;
            case refreshRetryNum:
              prevValue = String.valueOf(mRefreshRetryNum);
              mRefreshRetryNum = Integer.parseInt(value);
              break;
            case locationRefreshDelay:
              prevValue = String.valueOf(mLocationRefreshDelay);
              setLocationRefreshDelay(Integer.parseInt(value));
            case reInitDelay:
              prevValue = String.valueOf(mReInitDelay);
              mReInitDelay = Integer.parseInt(value);
              break;
            case facebookInfoDelay:
              prevValue = String.valueOf(mFacebookInfoDelay);
              mFacebookInfoDelay = Integer.parseInt(value);
              break;
            case twitterInfoDelay:
              prevValue = String.valueOf(mTwitterInfoDelay);
              mTwitterInfoDelay = Integer.parseInt(value);
              break;
            case openIn:
              prevValue = VALUE_OPEN_IN_BROWSER; // default
              mView.setOpenInBrowser(
                VALUE_OPEN_IN_BROWSER.equals(value)
              );
              break;
          }

          if (!cancelLogic && !mBackupParameterMap.containsKey(key)) {
            mBackupParameterMap.put(key, prevValue);
          }
        }
      }

      public void onSdkActionsLoaded(EnumMap<SdkAction, String> actions) {
        for(Entry<SdkAction, String> entry : actions.entrySet()) {
          SdkAction key = entry.getKey();
          String value = entry.getValue();

          switch (key) {
            case openLink:
              if (mRequest.isDisabledOpenLinkAction()) {
                Log.w(
                  LOGTAG,
                  String.format(
                    "'Open link' action was received, but actually disabled by request. Url was '%s'",
                    value
                  )
                );
              } else {
                openLink(value);
              }
              break;
          }
        }
      }

      public void onSdkChangeUid(String newUid) {
        mRequest.setUid(newUid);
      }
    });

    task.addRequestProperty("User-Agent", Plus1Helper.getUserAgent());
    task.addRequestProperty("x-original-user-agent", mView.getWebViewUserAgent());
  }

  private void openLink(String url)
  {
    Log.d(LOGTAG, "Open link url template: " + url);

    // TODO: add another parametrization
    url = url.replaceAll(Constants.PLACEHOLDER_REINIT_DELAY, String.valueOf(mReInitDelay));
    url = url.replaceAll(Constants.PLACEHOLDER_REFRESH_RETRY_NUM, String.valueOf(mRefreshRetryNum));
    url = url.replaceAll(Constants.PLACEHOLDER_BANNER_REFRESH_INTERVAL, String.valueOf(mRefreshDelay));
    url = url.replaceAll(Constants.PLACEHOLDER_FACEBOOK_INFO_REFRESH_INTERVAL, String.valueOf(mFacebookInfoDelay));
    url = url.replaceAll(Constants.PLACEHOLDER_TWITTER_INFO_REFRESH_INTERVAL, String.valueOf(mTwitterInfoDelay));
    url = url.replaceAll(Constants.PLACEHOLDER_UID, mRequest.getUID());

    try {
      url = url.replaceAll(
        Constants.PLACEHOLDER_ENCODED_CALLBACK,
        Base64.encodeBytes(mCallbackUrl.getBytes(), Base64.URL_SAFE)
      );
    } catch (IOException e) {
      Log.e(LOGTAG, "Failed to encode callback url: " + mCallbackUrl, e);
    }

    Log.d(LOGTAG, "Open link url after replacements: " + url);

    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    mView.getContext().getApplicationContext().startActivity(intent);
  }

  private void setLockForTask(InnerTask task, long seconds) {
    SimpleDateFormat df = new SimpleDateFormat(TASK_LOCK_DATE_FORMAT);

    Plus1Helper.setStorageValue(
      mView.getContext(),
      Constants.PREFERENCES_KEY_LOCK_TASK_PREFIX + task.toString(),
      df.format(new Date(System.currentTimeMillis() + seconds * 1000))
    );

    Log.d(
      LOGTAG,
      String.format("Locking task %s for %d seconds", task.toString(), seconds)
    );
  }

  private boolean hasLockForTask(InnerTask task) {
    SimpleDateFormat df = new SimpleDateFormat(TASK_LOCK_DATE_FORMAT);

    String key = Constants.PREFERENCES_KEY_LOCK_TASK_PREFIX + task.toString();
    String dateValue = Plus1Helper.getStorageValue(mView.getContext(), key);

    if (dateValue != null) {
      try {
        if (df.parse(dateValue).after(new Date()))
          return true;

        Plus1Helper.removeStorageValue(mView.getContext(), key);
      } catch (ParseException e) {
        Log.e(LOGTAG, "Strange date format in preferences: " + dateValue, e);
      }
    }

    return false;
  }
}




Java Source Code List

ru.wapstart.plus1.bart.BartActivity.java
ru.wapstart.plus1.sdk.AdView.java
ru.wapstart.plus1.sdk.ApplicationBrowser.java
ru.wapstart.plus1.sdk.Base64.java
ru.wapstart.plus1.sdk.BaseAdView.java
ru.wapstart.plus1.sdk.BaseRequestLoader.java
ru.wapstart.plus1.sdk.Constants.java
ru.wapstart.plus1.sdk.HtmlBannerDownloader.java
ru.wapstart.plus1.sdk.InitRequestLoader.java
ru.wapstart.plus1.sdk.JsonHelper.java
ru.wapstart.plus1.sdk.MraidAbstractController.java
ru.wapstart.plus1.sdk.MraidBrowserController.java
ru.wapstart.plus1.sdk.MraidCommandRegistry.java
ru.wapstart.plus1.sdk.MraidCommand.java
ru.wapstart.plus1.sdk.MraidDisplayController.java
ru.wapstart.plus1.sdk.MraidProperty.java
ru.wapstart.plus1.sdk.MraidView.java
ru.wapstart.plus1.sdk.Plus1AdAnimator.java
ru.wapstart.plus1.sdk.Plus1BannerAsker.java
ru.wapstart.plus1.sdk.Plus1BannerDownloadListener.java
ru.wapstart.plus1.sdk.Plus1BannerView.java
ru.wapstart.plus1.sdk.Plus1Helper.java
ru.wapstart.plus1.sdk.Plus1Request.java