package com.mopub.network; import android.content.Context; import android.graphics.Bitmap; import android.os.Looper; import android.support.annotation.NonNull; import android.support.v4.util.LruCache; import android.webkit.WebView; import com.mopub.common.ClientMetadata; import com.mopub.common.Preconditions; import com.mopub.common.VisibleForTesting; import com.mopub.common.util.DeviceUtils; import com.mopub.volley.Cache; import com.mopub.volley.Network; import com.mopub.volley.RequestQueue; import com.mopub.volley.toolbox.BasicNetwork; import com.mopub.volley.toolbox.DiskBasedCache; import com.mopub.volley.toolbox.HttpStack; import com.mopub.volley.toolbox.HurlStack; import com.mopub.volley.toolbox.ImageLoader; import java.io.File; public class Networking { private static final String CACHE_DIRECTORY_NAME = "mopub-volley-cache"; private static final int TEN_MB = 10 * 1024 * 1024; private static RequestQueue sRequestQueue; private static String sUserAgent; private static MaxWidthImageLoader sMaxWidthImageLoader; @NonNull public static RequestQueue getRequestQueue(@NonNull Context context) { RequestQueue requestQueue = sRequestQueue; // Double-check locking to initialize. if (requestQueue == null) { synchronized (Networking.class) { requestQueue = sRequestQueue; if (requestQueue == null) { // Guarantee ClientMetadata is set up. final ClientMetadata clientMetadata = ClientMetadata.getInstance(context); HurlStack.UrlRewriter urlRewriter = new PlayServicesUrlRewriter(clientMetadata.getDeviceId(), context); final String userAgent = Networking.getUserAgent(context.getApplicationContext()); HttpStack httpStack = new RequestQueueHttpStack(userAgent, urlRewriter); Network network = new BasicNetwork(httpStack); File volleyCacheDir = new File(context.getCacheDir().getPath() + File.separator + CACHE_DIRECTORY_NAME); Cache cache = new DiskBasedCache(volleyCacheDir, (int) DeviceUtils.diskCacheSizeBytes(volleyCacheDir, TEN_MB)); requestQueue = new RequestQueue(cache, network); sRequestQueue = requestQueue; sRequestQueue.start(); } } } return requestQueue; } @NonNull public static ImageLoader getImageLoader(@NonNull Context context) { MaxWidthImageLoader imageLoader = sMaxWidthImageLoader; // Double-check locking to initialize. if (imageLoader == null) { synchronized (Networking.class) { imageLoader = sMaxWidthImageLoader; if (imageLoader == null) { RequestQueue queue = getRequestQueue(context); int cacheSize = DeviceUtils.memoryCacheSizeBytes(context); final LruCache<String, Bitmap> imageCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { if (value != null) { return value.getRowBytes() * value.getHeight(); } return super.sizeOf(key, value); } }; imageLoader = new MaxWidthImageLoader(queue, context, new MaxWidthImageLoader.ImageCache() { @Override public Bitmap getBitmap(final String key) { return imageCache.get(key); } @Override public void putBitmap(final String key, final Bitmap bitmap) { imageCache.put(key, bitmap); } }); sMaxWidthImageLoader = imageLoader; } } } return imageLoader; } /** * Caches and returns the WebView user agent to be used across all SDK requests. This is * important because advertisers expect the same user agent across all request, impression, and * click events. */ @NonNull public static String getUserAgent(@NonNull Context context) { Preconditions.checkNotNull(context); String userAgent = sUserAgent; if (userAgent == null) { synchronized (Networking.class) { userAgent = sUserAgent; if (userAgent == null) { // As of Android 4.4, WebViews may only be instantiated on the UI thread if (Looper.myLooper() == Looper.getMainLooper()) { sUserAgent = new WebView(context).getSettings().getUserAgentString(); } else { // In the exceptional case where we can't access the WebView user agent, // fall back to the System-specific user agent. sUserAgent = System.getProperty("http.agent"); } } } } return sUserAgent; } @VisibleForTesting public static synchronized void clearForTesting() { sRequestQueue = null; sMaxWidthImageLoader = null; sUserAgent = null; } @VisibleForTesting public static synchronized void setRequestQueueForTesting(RequestQueue queue) { sRequestQueue = queue; } @VisibleForTesting public static synchronized void setImageLoaderForTesting(MaxWidthImageLoader imageLoader) { sMaxWidthImageLoader = imageLoader; } @VisibleForTesting public static synchronized void setUserAgentForTesting(String userAgent) { sUserAgent = userAgent; } }