Android Open Source - android-sdk Ad Fetch Task






From Project

Back to project page android-sdk.

License

The source code is released under:

Copyright (c) 2013 Adcash OU. All rights reserved under Creative Commons Attribution 3.0 Unported http://creativecommons.org/licenses/by/3.0/ Redistribution and use in source and binary forms, with or...

If you think the Android project 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) 2010-2013, Adcash OU.//  w  w w  .ja v a 2 s . c o m
 * All rights reserved.
 *
 * 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 'MoPub Inc.' 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 OWNER 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 com.adcash.mobileads;

import android.os.AsyncTask;
import android.util.Log;
import com.adcash.mobileads.factories.HttpClientFactory;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;

import static com.adcash.mobileads.util.HttpResponses.extractHeader;
import static com.adcash.mobileads.util.ResponseHeader.AD_TYPE;
import static com.adcash.mobileads.util.ResponseHeader.USER_AGENT;
import static com.adcash.mobileads.util.ResponseHeader.WARMUP;

public class AdFetchTask extends AsyncTask<String, Void, AdLoadTask> {
    private TaskTracker mTaskTracker;
    private AdViewController mAdViewController;
    private Exception mException;
    private HttpClient mHttpClient;
    private long mTaskId;
    private String mUserAgent;

    private AdFetcher.FetchStatus mFetchStatus = AdFetcher.FetchStatus.NOT_SET;
    private static final int MAXIMUM_REFRESH_TIME_MILLISECONDS = 600000;
    private static final double EXPONENTIAL_BACKOFF_FACTOR = 1.5;

    public AdFetchTask(TaskTracker taskTracker, AdViewController adViewController, String userAgent, int timeoutMilliseconds) {
        mTaskTracker = taskTracker;

        mAdViewController = adViewController;
        mHttpClient = HttpClientFactory.create(timeoutMilliseconds);
        mTaskId = mTaskTracker.getCurrentTaskId();
        mUserAgent = userAgent;
    }

    @Override
    protected AdLoadTask doInBackground(String... urls) {
        AdLoadTask result = null;
        try {
            result = fetch(urls[0]);
        } catch (Exception exception) {
            mException = exception;
        } finally {
            shutdownHttpClient();
        }
        return result;
    }

    private AdLoadTask fetch(String url) throws Exception {
        HttpGet httpget = new HttpGet(url);
        httpget.addHeader(USER_AGENT.getKey(), mUserAgent);

        if (!isStateValid()) return null;

        HttpResponse response = mHttpClient.execute(httpget);

        if (!isResponseValid(response)) return null;

        mAdViewController.configureUsingHttpResponse(response);

        if (!responseContainsContent(response)) return null;

        return AdLoadTask.fromHttpResponse(response, mAdViewController);
    }

    private boolean responseContainsContent(HttpResponse response) {
        // Ensure that the ad is not warming up.
        if ("1".equals(extractHeader(response, WARMUP))) {
            Log.d("Adcash", "Ad Unit (" + mAdViewController.getAdUnitId() + ") is still warming up. " +
                    "Please try again in a few minutes.");
            mFetchStatus = AdFetcher.FetchStatus.AD_WARMING_UP;
            return false;
        }

        // Ensure that the ad type header is valid and not "clear".
        String adType = extractHeader(response, AD_TYPE);
        if ("clear".equals(adType)) {
            Log.d("Adcash", "No inventory found for adunit (" + mAdViewController.getAdUnitId() + ").");
            mFetchStatus = AdFetcher.FetchStatus.CLEAR_AD_TYPE;
            return false;
        }

        return true;
    }

    private boolean isResponseValid(HttpResponse response) {
        if (response == null || response.getEntity() == null) {
            Log.d("Adcash", "Adcash server returned null response.");
            mFetchStatus = AdFetcher.FetchStatus.INVALID_SERVER_RESPONSE_NOBACKOFF;
            return false;
        }

        final int statusCode = response.getStatusLine().getStatusCode();

        // Client and Server HTTP errors should result in an exponential backoff
        if (statusCode >= 400) {
            Log.d("Adcash", "Server error: returned HTTP status code " + Integer.toString(statusCode) +
                    ". Please try again.");
            mFetchStatus = AdFetcher.FetchStatus.INVALID_SERVER_RESPONSE_BACKOFF;
            return false;
        }
        // Other non-200 HTTP status codes should still fail
        else if (statusCode != HttpStatus.SC_OK) {
            Log.d("Adcash", "Adcash server returned invalid response: HTTP status code " +
                    Integer.toString(statusCode) + ".");
            mFetchStatus = AdFetcher.FetchStatus.INVALID_SERVER_RESPONSE_NOBACKOFF;
            return false;
        }
        return true;
    }

    private boolean isStateValid() {
        // We check to see if this AsyncTask was cancelled, as per
        // http://developer.android.com/reference/android/os/AsyncTask.html
        if (isCancelled()) {
            mFetchStatus = AdFetcher.FetchStatus.FETCH_CANCELLED;
            return false;
        }

        if (mAdViewController == null || mAdViewController.isDestroyed()) {
            Log.d("Adcash", "Error loading ad: AdViewController has already been GCed or destroyed.");
            return false;
        }
        return true;
    }

    @Override
    protected void onPostExecute(AdLoadTask adLoadTask) {
        if (!isMostCurrentTask()) {
            Log.d("Adcash", "Ad response is stale.");
            cleanup();
            return;
        }

        // If cleanup() has already been called on the AdViewController, don't proceed.
        if (mAdViewController == null || mAdViewController.isDestroyed()) {
            if (adLoadTask != null) {
                adLoadTask.cleanup();
            }
            mTaskTracker.markTaskCompleted(mTaskId);
            cleanup();
            return;
        }

        if (adLoadTask == null) {
            if (mException != null) {
                Log.d("Adcash", "Exception caught while loading ad: " + mException);
            }

            AdcashErrorCode errorCode;
            switch (mFetchStatus) {
                case NOT_SET:
                    errorCode = AdcashErrorCode.UNSPECIFIED;
                    break;
                case FETCH_CANCELLED:
                    errorCode = AdcashErrorCode.CANCELLED;
                    break;
                case INVALID_SERVER_RESPONSE_BACKOFF:
                case INVALID_SERVER_RESPONSE_NOBACKOFF:
                    errorCode = AdcashErrorCode.SERVER_ERROR;
                    break;
                case CLEAR_AD_TYPE:
                case AD_WARMING_UP:
                    errorCode = AdcashErrorCode.NO_FILL;
                    break;
                default:
                    errorCode = AdcashErrorCode.UNSPECIFIED;
                    break;
            }

            mAdViewController.adDidFail(errorCode);

            /*
             * There are numerous reasons for the ad fetch to fail, but only in the specific
             * case of actual server failure should we exponentially back off.
             *
             * Note: We place the exponential backoff after AdViewController's adDidFail because we only
             * want to increase refresh times after the first failure refresh timer is
             * scheduled, and not before.
             */
            if (mFetchStatus == AdFetcher.FetchStatus.INVALID_SERVER_RESPONSE_BACKOFF) {
                exponentialBackoff();
                mFetchStatus = AdFetcher.FetchStatus.NOT_SET;
            }
        } else {
            adLoadTask.execute();
            adLoadTask.cleanup();
        }

        mTaskTracker.markTaskCompleted(mTaskId);
        cleanup();
    }

    @Override
    protected void onCancelled() {
        if (!isMostCurrentTask()) {
            Log.d("Adcash", "Ad response is stale.");
            cleanup();
            return;
        }

        Log.d("Adcash", "Ad loading was cancelled.");
        if (mException != null) {
            Log.d("Adcash", "Exception caught while loading ad: " + mException);
        }
        mTaskTracker.markTaskCompleted(mTaskId);
        cleanup();
    }

    /* This helper function is called when a 4XX or 5XX error is received during an ad fetch.
     * It exponentially increases the parent AdViewController's refreshTime up to a specified cap.
     */
    private void exponentialBackoff() {
        if (mAdViewController == null) {
            return;
        }

        int refreshTimeMilliseconds = mAdViewController.getRefreshTimeMilliseconds();

        refreshTimeMilliseconds = (int) (refreshTimeMilliseconds * EXPONENTIAL_BACKOFF_FACTOR);
        if (refreshTimeMilliseconds > MAXIMUM_REFRESH_TIME_MILLISECONDS) {
            refreshTimeMilliseconds = MAXIMUM_REFRESH_TIME_MILLISECONDS;
        }

        mAdViewController.setRefreshTimeMilliseconds(refreshTimeMilliseconds);
    }

    private void cleanup() {
        mTaskTracker = null;
        mException = null;
        mFetchStatus = AdFetcher.FetchStatus.NOT_SET;
    }

    private void shutdownHttpClient() {
        if (mHttpClient != null) {
            ClientConnectionManager manager = mHttpClient.getConnectionManager();
            if (manager != null) {
                manager.shutdown();
            }
            mHttpClient = null;
        }
    }

    private boolean isMostCurrentTask() {
        // if we've been cleaned up already, then we're definitely not the current task
        return (mTaskTracker == null) ? false : mTaskTracker.isMostCurrentTask(mTaskId);
    }
}




Java Source Code List

com.adcash.mobileads.AdAlertGestureListener.java
com.adcash.mobileads.AdAlertReporter.java
com.adcash.mobileads.AdConfiguration.java
com.adcash.mobileads.AdFetchTask.java
com.adcash.mobileads.AdFetcher.java
com.adcash.mobileads.AdLoadTask.java
com.adcash.mobileads.AdTypeTranslator.java
com.adcash.mobileads.AdUrlGenerator.java
com.adcash.mobileads.AdViewController.java
com.adcash.mobileads.AdcashActivity.java
com.adcash.mobileads.AdcashConversionTracker.java
com.adcash.mobileads.AdcashErrorCode.java
com.adcash.mobileads.AdcashInterstitial.java
com.adcash.mobileads.AdcashReferrerReceiver.java
com.adcash.mobileads.AdcashView.java
com.adcash.mobileads.Adcash.java
com.adcash.mobileads.BaseHtmlWebView.java
com.adcash.mobileads.BaseInterstitialActivity.java
com.adcash.mobileads.BaseUrlGenerator.java
com.adcash.mobileads.BaseVideoView.java
com.adcash.mobileads.BaseWebView.java
com.adcash.mobileads.CustomEventBannerAdapter.java
com.adcash.mobileads.CustomEventBanner.java
com.adcash.mobileads.CustomEventInterstitialAdapter.java
com.adcash.mobileads.CustomEventInterstitial.java
com.adcash.mobileads.DefaultBannerAdListener.java
com.adcash.mobileads.DefaultInterstitialAdListener.java
com.adcash.mobileads.DiskLruCache.java
com.adcash.mobileads.EventForwardingBroadcastReceiver.java
com.adcash.mobileads.FacebookKeywordProvider.java
com.adcash.mobileads.GpsHelper.java
com.adcash.mobileads.HtmlBannerWebView.java
com.adcash.mobileads.HtmlBanner.java
com.adcash.mobileads.HtmlInterstitialWebView.java
com.adcash.mobileads.HtmlInterstitial.java
com.adcash.mobileads.HtmlWebViewClient.java
com.adcash.mobileads.HtmlWebViewListener.java
com.adcash.mobileads.Log.java
com.adcash.mobileads.MraidAbstractController.java
com.adcash.mobileads.MraidActivity.java
com.adcash.mobileads.MraidBanner.java
com.adcash.mobileads.MraidBrowserController.java
com.adcash.mobileads.MraidBrowser.java
com.adcash.mobileads.MraidCommandFactory.java
com.adcash.mobileads.MraidCommandRegistry.java
com.adcash.mobileads.MraidCommand.java
com.adcash.mobileads.MraidDisplayController.java
com.adcash.mobileads.MraidInterstitial.java
com.adcash.mobileads.MraidProperty.java
com.adcash.mobileads.MraidVideoPlayerActivity.java
com.adcash.mobileads.MraidVideoView.java
com.adcash.mobileads.MraidView.java
com.adcash.mobileads.ResponseBodyInterstitial.java
com.adcash.mobileads.SharedPreferencesHelper.java
com.adcash.mobileads.TaskTracker.java
com.adcash.mobileads.Utils.java
com.adcash.mobileads.VastVideoDownloadTask.java
com.adcash.mobileads.VastVideoInterstitial.java
com.adcash.mobileads.VastVideoView.java
com.adcash.mobileads.ViewGestureDetector.java
com.adcash.mobileads.factories.AdFetchTaskFactory.java
com.adcash.mobileads.factories.AdFetcherFactory.java
com.adcash.mobileads.factories.AdViewControllerFactory.java
com.adcash.mobileads.factories.AdcashViewFactory.java
com.adcash.mobileads.factories.CustomEventBannerAdapterFactory.java
com.adcash.mobileads.factories.CustomEventBannerFactory.java
com.adcash.mobileads.factories.CustomEventInterstitialAdapterFactory.java
com.adcash.mobileads.factories.CustomEventInterstitialFactory.java
com.adcash.mobileads.factories.HtmlBannerWebViewFactory.java
com.adcash.mobileads.factories.HtmlInterstitialWebViewFactory.java
com.adcash.mobileads.factories.HttpClientFactory.java
com.adcash.mobileads.factories.MraidViewFactory.java
com.adcash.mobileads.factories.VastManagerFactory.java
com.adcash.mobileads.factories.VastVideoDownloadTaskFactory.java
com.adcash.mobileads.factories.ViewGestureDetectorFactory.java
com.adcash.mobileads.resource.Drawables.java
com.adcash.mobileads.resource.MraidJavascript.java
com.adcash.mobileads.util.AsyncTasks.java
com.adcash.mobileads.util.Base64.java
com.adcash.mobileads.util.DateAndTime.java
com.adcash.mobileads.util.Dips.java
com.adcash.mobileads.util.Files.java
com.adcash.mobileads.util.HttpClients.java
com.adcash.mobileads.util.HttpResponses.java
com.adcash.mobileads.util.HttpUtils.java
com.adcash.mobileads.util.Json.java
com.adcash.mobileads.util.Lists.java
com.adcash.mobileads.util.Mraids.java
com.adcash.mobileads.util.Reflection.java
com.adcash.mobileads.util.ResponseHeader.java
com.adcash.mobileads.util.Streams.java
com.adcash.mobileads.util.Strings.java
com.adcash.mobileads.util.VersionCode.java
com.adcash.mobileads.util.Views.java
com.adcash.mobileads.util.WebViews.java
com.adcash.mobileads.util.vast.VastManager.java
com.adcash.mobileads.util.vast.VastXmlManager.java