/*
* Copyright (c) 2010, MoPub Inc.
* 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.mopub.mobileads;
import java.io.IOException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.location.Location;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings.Secure;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import com.mopub.mobileads.MoPubView.LocationAwareness;
public class AdView extends WebView {
public static final String AD_ORIENTATION_PORTRAIT_ONLY = "p";
public static final String AD_ORIENTATION_LANDSCAPE_ONLY = "l";
public static final String AD_ORIENTATION_BOTH = "b";
public static final String DEVICE_ORIENTATION_PORTRAIT = "p";
public static final String DEVICE_ORIENTATION_LANDSCAPE = "l";
public static final String DEVICE_ORIENTATION_SQUARE = "s";
public static final String DEVICE_ORIENTATION_UNKNOWN = "u";
public static final String EXTRA_AD_CLICK_DATA = "com.mopub.intent.extra.AD_CLICK_DATA";
private static final int MINIMUM_REFRESH_TIME_MILLISECONDS = 10000;
private static final FrameLayout.LayoutParams WRAP_AND_CENTER_LAYOUT_PARAMS =
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER);
private String mAdUnitId;
private String mKeywords;
private String mUrl;
private String mClickthroughUrl;
private String mRedirectUrl;
private String mFailUrl;
private String mImpressionUrl;
private Location mLocation;
private boolean mIsLoading;
private boolean mAutorefreshEnabled;
private boolean mTesting;
private int mRefreshTimeMilliseconds = 60000;
private int mWidth;
private int mHeight;
private String mAdOrientation;
private Map<String, Object> mLocalExtras = new HashMap<String, Object>();
protected MoPubView mMoPubView;
private String mResponseString;
private String mUserAgent;
private boolean mIsDestroyed;
private final Handler mHandler = new Handler();
private AdFetcher mAdFetcher;
public AdView(Context context, MoPubView view) {
/* Important: don't allow any WebView subclass to be instantiated using
* an Activity context, as it will leak on Froyo devices and earlier.
*/
super(context.getApplicationContext());
mMoPubView = view;
mAutorefreshEnabled = true;
/* Store user agent string at beginning to prevent NPE during background
* thread operations.
*/
mUserAgent = getSettings().getUserAgentString();
mAdFetcher = new AdFetcher(this, mUserAgent);
disableScrollingAndZoom();
getSettings().setJavaScriptEnabled(true);
getSettings().setPluginsEnabled(true);
setBackgroundColor(Color.TRANSPARENT);
setWebViewClient(new AdWebViewClient());
addMoPubUriJavascriptInterface();
}
private void disableScrollingAndZoom() {
setHorizontalScrollBarEnabled(false);
setHorizontalScrollbarOverlay(false);
setVerticalScrollBarEnabled(false);
setVerticalScrollbarOverlay(false);
getSettings().setSupportZoom(false);
}
/* XXX (2/15/12): This is a workaround for a problem on ICS devices where
* WebViews with layout height WRAP_CONTENT can mysteriously render with
* zero height. This seems to happen when calling loadData() with HTML that
* sets window.location during its "onload" event. We use loadData() when
* displaying interstitials, and our creatives use window.location to
* communicate ad loading status to AdViews. This results in zero-height
* interstitials. We counteract this by using a Javascript interface object
* to signal loading status, rather than modifying window.location.
*/
private void addMoPubUriJavascriptInterface() {
final class MoPubUriJavascriptInterface {
// This method appears to be unused, since it will only be called from JavaScript.
@SuppressWarnings("unused")
public boolean fireFinishLoad() {
AdView.this.postHandlerRunnable(new Runnable() {
@Override
public void run() {
AdView.this.adDidLoad();
}
});
return true;
}
}
addJavascriptInterface(new MoPubUriJavascriptInterface(), "mopubUriInterface");
}
private void postHandlerRunnable(Runnable r) {
mHandler.post(r);
}
private class AdWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
AdView adView = (AdView) view;
// Handle the special mopub:// scheme calls.
if (url.startsWith("mopub://")) {
Uri uri = Uri.parse(url);
String host = uri.getHost();
if (host.equals("finishLoad")) adView.adDidLoad();
else if (host.equals("close")) adView.adDidClose();
else if (host.equals("failLoad")) adView.loadFailUrl(MoPubErrorCode.UNSPECIFIED);
else if (host.equals("custom")) adView.handleCustomIntentFromUri(uri);
return true;
}
// Handle other phone intents.
else if (url.startsWith("tel:") || url.startsWith("voicemail:") ||
url.startsWith("sms:") || url.startsWith("mailto:") ||
url.startsWith("geo:") || url.startsWith("google.streetview:")) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
getContext().startActivity(intent);
registerClick();
} catch (ActivityNotFoundException e) {
Log.w("MoPub", "Could not handle intent with URI: " + url +
". Is this intent unsupported on your phone?");
}
return true;
}
// Fast fail if market:// intent is called when Google Play is not installed
else if (url.startsWith("market://")) {
// Determine which activities can handle the market intent
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
PackageManager packageManager = getContext().getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
// If there are no relevant activities, don't follow the link
boolean isIntentSafe = activities.size() > 0;
if (!isIntentSafe) {
Log.w("MoPub", "Could not handle market action: " + url
+ ". Perhaps you're running in the emulator, which does not have "
+ "the Android Market?");
return true;
}
}
url = urlWithClickTrackingRedirect(adView, url);
Log.d("MoPub", "Ad clicked. Click URL: " + url);
mMoPubView.adClicked();
showBrowserForUrl(url);
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// If the URL being loaded shares the redirectUrl prefix, open it in the browser.
AdView adView = (AdView) view;
String redirectUrl = adView.getRedirectUrl();
if (redirectUrl != null && url.startsWith(redirectUrl)) {
url = urlWithClickTrackingRedirect(adView, url);
view.stopLoading();
showBrowserForUrl(url);
}
}
private String urlWithClickTrackingRedirect(AdView adView, String url) {
String clickthroughUrl = adView.getClickthroughUrl();
if (clickthroughUrl == null) return url;
else {
String encodedUrl = Uri.encode(url);
return clickthroughUrl + "&r=" + encodedUrl;
}
}
}
public void loadAd() {
if (mAdUnitId == null) {
Log.d("MoPub", "Can't load an ad in this ad view because the ad unit ID is null. " +
"Did you forget to call setAdUnitId()?");
return;
}
if (!isNetworkAvailable()) {
Log.d("MoPub", "Can't load an ad because there is no network connectivity.");
scheduleRefreshTimerIfEnabled();
return;
}
if (mLocation == null) mLocation = getLastKnownLocation();
String adUrl = generateAdUrl();
loadUrl(adUrl);
}
private boolean isNetworkAvailable() {
Context context = getContext();
// If we don't have network state access, just assume the network is up.
String permission = android.Manifest.permission.ACCESS_NETWORK_STATE;
int result = context.checkCallingPermission(permission);
if (result == PackageManager.PERMISSION_DENIED) return true;
// Otherwise, perform the connectivity check.
ConnectivityManager cm
= (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
/*
* Returns the last known location of the device using its GPS and network location providers.
* May be null if:
* - Location permissions are not requested in the Android manifest file
* - The location providers don't exist
* - Location awareness is disabled in the parent MoPubView
*/
private Location getLastKnownLocation() {
LocationAwareness locationAwareness = mMoPubView.getLocationAwareness();
int locationPrecision = mMoPubView.getLocationPrecision();
Location result = null;
if (locationAwareness == LocationAwareness.LOCATION_AWARENESS_DISABLED) {
return null;
}
LocationManager lm
= (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
Location gpsLocation = null;
try {
gpsLocation = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (SecurityException e) {
Log.d("MoPub", "Failed to retrieve GPS location: access appears to be disabled.");
} catch (IllegalArgumentException e) {
Log.d("MoPub", "Failed to retrieve GPS location: device has no GPS provider.");
}
Location networkLocation = null;
try {
networkLocation = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
} catch (SecurityException e) {
Log.d("MoPub", "Failed to retrieve network location: access appears to be disabled.");
} catch (IllegalArgumentException e) {
Log.d("MoPub", "Failed to retrieve network location: device has no network provider.");
}
if (gpsLocation == null && networkLocation == null) {
return null;
}
else if (gpsLocation != null && networkLocation != null) {
if (gpsLocation.getTime() > networkLocation.getTime()) result = gpsLocation;
else result = networkLocation;
}
else if (gpsLocation != null) result = gpsLocation;
else result = networkLocation;
// Truncate latitude/longitude to the number of digits specified by locationPrecision.
if (locationAwareness == LocationAwareness.LOCATION_AWARENESS_TRUNCATED) {
double lat = result.getLatitude();
double truncatedLat = BigDecimal.valueOf(lat)
.setScale(locationPrecision, BigDecimal.ROUND_HALF_DOWN)
.doubleValue();
result.setLatitude(truncatedLat);
double lon = result.getLongitude();
double truncatedLon = BigDecimal.valueOf(lon)
.setScale(locationPrecision, BigDecimal.ROUND_HALF_DOWN)
.doubleValue();
result.setLongitude(truncatedLon);
}
return result;
}
private String generateAdUrl() {
StringBuilder sz = new StringBuilder("http://" + getServerHostname() +
MoPubView.AD_HANDLER);
sz.append("?v=6&id=" + mAdUnitId);
sz.append("&nv=" + MoPub.SDK_VERSION);
String udid = Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID);
String udidDigest = (udid == null) ? "" : Utils.sha1(udid);
sz.append("&udid=sha:" + udidDigest);
String keywords = addKeyword(mKeywords, getFacebookKeyword());
if (keywords != null && keywords.length() > 0) {
sz.append("&q=" + Uri.encode(keywords));
}
if (mLocation != null) {
sz.append("&ll=" + mLocation.getLatitude() + "," + mLocation.getLongitude());
}
sz.append("&z=" + getTimeZoneOffsetString());
int orientation = getResources().getConfiguration().orientation;
String orString = DEVICE_ORIENTATION_UNKNOWN;
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
orString = DEVICE_ORIENTATION_PORTRAIT;
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
orString = DEVICE_ORIENTATION_LANDSCAPE;
} else if (orientation == Configuration.ORIENTATION_SQUARE) {
orString = DEVICE_ORIENTATION_SQUARE;
}
sz.append("&o=" + orString);
float density = getContext().getResources().getDisplayMetrics().density;
sz.append("&sc_a=" + density);
boolean mraid = true;
try {
Class.forName("com.mopub.mobileads.MraidView");
} catch (ClassNotFoundException e) {
mraid = false;
}
if (mraid) sz.append("&mr=1");
return sz.toString();
}
private String getTimeZoneOffsetString() {
SimpleDateFormat format = new SimpleDateFormat("Z");
format.setTimeZone(TimeZone.getDefault());
return format.format(new Date());
}
private String getFacebookKeyword() {
try {
Class<?> facebookKeywordProviderClass = Class.forName("com.mopub.mobileads.FacebookKeywordProvider");
Method getKeywordMethod = facebookKeywordProviderClass.getMethod("getKeyword", Context.class);
return (String) getKeywordMethod.invoke(facebookKeywordProviderClass, getContext());
} catch (Exception exception) {
return null;
}
}
/*
* Overrides the WebView's loadUrl() in order to expose HTTP response headers.
*/
@Override
public void loadUrl(String url) {
if (url.startsWith("javascript:")) {
super.loadUrl(url);
return;
}
if (mIsLoading) {
Log.i("MoPub", "Already loading an ad for " + mAdUnitId + ", wait to finish.");
return;
}
mFailUrl = null;
mUrl = url;
mIsLoading = true;
if (mAdFetcher != null) {
mAdFetcher.fetchAdForUrl(mUrl);
}
}
protected void configureAdViewUsingHeadersFromHttpResponse(HttpResponse response) {
// Print the ad network type to the console.
Header ntHeader = response.getFirstHeader("X-Networktype");
if (ntHeader != null) Log.i("MoPub", "Fetching ad network type: " + ntHeader.getValue());
// Set the redirect URL prefix: navigating to any matching URLs will send us to the browser.
Header rdHeader = response.getFirstHeader("X-Launchpage");
if (rdHeader != null) mRedirectUrl = rdHeader.getValue();
else mRedirectUrl = null;
// Set the URL that is prepended to links for click-tracking purposes.
Header ctHeader = response.getFirstHeader("X-Clickthrough");
if (ctHeader != null) mClickthroughUrl = ctHeader.getValue();
else mClickthroughUrl = null;
// Set the fall-back URL to be used if the current request fails.
Header flHeader = response.getFirstHeader("X-Failurl");
if (flHeader != null) mFailUrl = flHeader.getValue();
else mFailUrl = null;
// Set the URL to be used for impression tracking.
Header imHeader = response.getFirstHeader("X-Imptracker");
if (imHeader != null) mImpressionUrl = imHeader.getValue();
else mImpressionUrl = null;
// Set the webview's scrollability.
Header scHeader = response.getFirstHeader("X-Scrollable");
boolean enabled = false;
if (scHeader != null) enabled = scHeader.getValue().equals("1");
setWebViewScrollingEnabled(enabled);
// Set the width and height.
Header wHeader = response.getFirstHeader("X-Width");
Header hHeader = response.getFirstHeader("X-Height");
if (wHeader != null && hHeader != null) {
mWidth = Integer.parseInt(wHeader.getValue().trim());
mHeight = Integer.parseInt(hHeader.getValue().trim());
}
else {
mWidth = 0;
mHeight = 0;
}
// Set the auto-refresh time. A timer will be scheduled upon ad success or failure.
Header rtHeader = response.getFirstHeader("X-Refreshtime");
if (rtHeader != null) {
mRefreshTimeMilliseconds = Integer.valueOf(rtHeader.getValue()) * 1000;
if (mRefreshTimeMilliseconds < MINIMUM_REFRESH_TIME_MILLISECONDS) {
mRefreshTimeMilliseconds = MINIMUM_REFRESH_TIME_MILLISECONDS;
}
}
else mRefreshTimeMilliseconds = 0;
// Set the allowed orientations for this ad.
Header orHeader = response.getFirstHeader("X-Orientation");
mAdOrientation = (orHeader != null) ? orHeader.getValue() : null;
}
private void setWebViewScrollingEnabled(boolean enabled) {
if (enabled) {
setOnTouchListener(null);
} else {
setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
});
}
}
private void adDidLoad() {
Log.i("MoPub", "Ad successfully loaded.");
mIsLoading = false;
scheduleRefreshTimerIfEnabled();
setAdContentView(this, getHtmlAdLayoutParams());
mMoPubView.adLoaded();
}
public void setAdContentView(View view) {
setAdContentView(view, WRAP_AND_CENTER_LAYOUT_PARAMS);
}
private void setAdContentView(View view, FrameLayout.LayoutParams layoutParams) {
mMoPubView.removeAllViews();
mMoPubView.addView(view, layoutParams);
}
private FrameLayout.LayoutParams getHtmlAdLayoutParams() {
if (mWidth > 0 && mHeight > 0) {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int scaledWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mWidth,
displayMetrics);
int scaledHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mHeight,
displayMetrics);
return new FrameLayout.LayoutParams(scaledWidth, scaledHeight, Gravity.CENTER);
} else {
return WRAP_AND_CENTER_LAYOUT_PARAMS;
}
}
void adDidFail(MoPubErrorCode errorCode) {
Log.i("MoPub", "Ad failed to load.");
mIsLoading = false;
scheduleRefreshTimerIfEnabled();
mMoPubView.adFailed(errorCode);
}
private void adDidClose() {
mMoPubView.adClosed();
}
private void handleCustomIntentFromUri(Uri uri) {
registerClick();
String action = uri.getQueryParameter("fnc");
String adData = uri.getQueryParameter("data");
Intent customIntent = new Intent(action);
customIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (adData != null) customIntent.putExtra(EXTRA_AD_CLICK_DATA, adData);
try {
getContext().startActivity(customIntent);
} catch (ActivityNotFoundException e) {
Log.w("MoPub", "Could not handle custom intent: " + action +
". Is your intent spelled correctly?");
}
}
private void showBrowserForUrl(String url) {
if (this.isDestroyed()) return;
if (url == null || url.equals("")) url = "about:blank";
Log.d("MoPub", "Final URI to show in browser: " + url);
Context context = getContext();
Intent intent = new Intent(context, MraidBrowser.class);
intent.putExtra(MraidBrowser.URL_EXTRA, url);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
String action = intent.getAction();
Log.w("MoPub", "Could not handle intent action: " + action
+ ". Perhaps you forgot to declare com.mopub.mobileads.MraidBrowser"
+ " in your Android manifest file.");
getContext().startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse("about:blank"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
}
@Deprecated
public void customEventDidLoadAd() {
mIsLoading = false;
trackImpression();
scheduleRefreshTimerIfEnabled();
}
@Deprecated
public void customEventDidFailToLoadAd() {
loadFailUrl(MoPubErrorCode.UNSPECIFIED);
}
@Deprecated
public void customEventActionWillBegin() {
registerClick();
}
protected boolean isDestroyed() {
return mIsDestroyed;
}
/*
* Clean up the internal state of the AdView.
*/
protected void cleanup() {
if (mIsDestroyed) {
return;
}
setAutorefreshEnabled(false);
cancelRefreshTimer();
destroy();
// WebView subclasses are not garbage-collected in a timely fashion on Froyo and below,
// thanks to some persistent references in WebViewCore. We manually release some resources
// to compensate for this "leak".
mAdFetcher.cleanup();
mAdFetcher = null;
mLocalExtras = null;
mResponseString = null;
mMoPubView.removeView(this);
mMoPubView = null;
// Flag as destroyed. LoadUrlTask checks this before proceeding in its onPostExecute().
mIsDestroyed = true;
}
@Override
public void reload() {
Log.d("MoPub", "Reload ad: " + mUrl);
loadUrl(mUrl);
}
public void loadFailUrl(MoPubErrorCode errorCode) {
mIsLoading = false;
Log.v("MoPub", "MoPubErrorCode: " + errorCode.toString());
if (mFailUrl != null) {
Log.d("MoPub", "Loading failover url: " + mFailUrl);
loadUrl(mFailUrl);
} else {
// No other URLs to try, so signal a failure.
adDidFail(MoPubErrorCode.NO_FILL);
}
}
protected void loadResponseString(String responseString) {
loadDataWithBaseURL("http://" + getServerHostname() + "/", responseString, "text/html",
"utf-8", null);
}
protected void trackImpression() {
new Thread(new Runnable() {
public void run () {
if (mImpressionUrl == null) return;
DefaultHttpClient httpclient = new DefaultHttpClient();
try {
HttpGet httpget = new HttpGet(mImpressionUrl);
httpget.addHeader("User-Agent", mUserAgent);
httpclient.execute(httpget);
} catch (IllegalArgumentException e) {
Log.d("MoPub", "Impression tracking failed (IllegalArgumentException): "+mImpressionUrl);
} catch (ClientProtocolException e) {
Log.d("MoPub", "Impression tracking failed (ClientProtocolException): "+mImpressionUrl);
} catch (IOException e) {
Log.d("MoPub", "Impression tracking failed (IOException): "+mImpressionUrl);
} finally {
httpclient.getConnectionManager().shutdown();
}
}
}).start();
}
protected void registerClick() {
new Thread(new Runnable() {
public void run () {
if (mClickthroughUrl == null) return;
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(mClickthroughUrl);
httpget.addHeader("User-Agent", mUserAgent);
try {
httpclient.execute(httpget);
} catch (ClientProtocolException e) {
Log.i("MoPub", "Click tracking failed: "+mClickthroughUrl);
} catch (IOException e) {
Log.i("MoPub", "Click tracking failed: "+mClickthroughUrl);
} finally {
httpclient.getConnectionManager().shutdown();
}
}
}).start();
}
protected void adAppeared() {
this.loadUrl("javascript:webviewDidAppear();");
}
private Handler mRefreshHandler = new Handler();
private Runnable mRefreshRunnable = new Runnable() {
public void run() {
loadAd();
}
};
protected void scheduleRefreshTimerIfEnabled() {
cancelRefreshTimer();
if (!mAutorefreshEnabled || mRefreshTimeMilliseconds <= 0) return;
mRefreshHandler.postDelayed(mRefreshRunnable, mRefreshTimeMilliseconds);
}
protected void cancelRefreshTimer() {
mRefreshHandler.removeCallbacks(mRefreshRunnable);
}
protected int getRefreshTimeMilliseconds() {
return mRefreshTimeMilliseconds;
}
protected void setRefreshTimeMilliseconds(int refreshTimeMilliseconds) {
mRefreshTimeMilliseconds = refreshTimeMilliseconds;
}
private String addKeyword(String keywords, String addition) {
if (addition == null || addition.length() == 0) {
return keywords;
} else if (keywords == null || keywords.length() == 0) {
return addition;
} else {
return keywords + "," + addition;
}
}
protected String getServerHostname() {
return mTesting ? MoPubView.HOST_FOR_TESTING : MoPubView.HOST;
}
////////////////////////////////////////////////////////////////////////////////////////////////
public String getKeywords() {
return mKeywords;
}
public void setKeywords(String keywords) {
mKeywords = keywords;
}
public Location getLocation() {
return mLocation;
}
public void setLocation(Location location) {
mLocation = location;
}
public String getAdUnitId() {
return mAdUnitId;
}
public void setAdUnitId(String adUnitId) {
mAdUnitId = adUnitId;
}
public void setTimeout(int milliseconds) {
if (mAdFetcher != null) {
mAdFetcher.setTimeout(milliseconds);
}
}
public int getAdWidth() {
return mWidth;
}
public int getAdHeight() {
return mHeight;
}
public String getAdOrientation() {
return mAdOrientation;
}
public String getClickthroughUrl() {
return mClickthroughUrl;
}
public void setClickthroughUrl(String url) {
mClickthroughUrl = url;
}
public String getRedirectUrl() {
return mRedirectUrl;
}
public String getResponseString() {
return mResponseString;
}
protected void setResponseString(String responseString) {
mResponseString = responseString;
}
protected void setIsLoading(boolean isLoading) {
mIsLoading = isLoading;
}
public void setAutorefreshEnabled(boolean enabled) {
mAutorefreshEnabled = enabled;
Log.d("MoPub", "Automatic refresh for " + mAdUnitId + " set to: " + enabled + ".");
if (!mAutorefreshEnabled) cancelRefreshTimer();
else scheduleRefreshTimerIfEnabled();
}
public boolean getAutorefreshEnabled() {
return mAutorefreshEnabled;
}
public void setTesting(boolean testing) {
mTesting = testing;
}
public boolean getTesting() {
return mTesting;
}
public void forceRefresh() {
mIsLoading = false;
loadAd();
}
void setLocalExtras(Map<String, Object> localExtras) {
mLocalExtras = (localExtras != null)
? new HashMap<String,Object>(localExtras)
: new HashMap<String,Object>();
}
Map<String, Object> getLocalExtras() {
return (mLocalExtras != null)
? new HashMap<String,Object>(mLocalExtras)
: new HashMap<String,Object>();
}
}