package com.mopub.common.util;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.StatFs;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.util.DisplayMetrics;
import android.view.Surface;
import com.mopub.common.logging.MoPubLog;
import org.apache.http.conn.util.InetAddressUtils;
import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Locale;
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.INTERNET;
import static com.mopub.common.util.Reflection.MethodBuilder;
import static com.mopub.common.util.VersionCode.HONEYCOMB;
import static com.mopub.common.util.VersionCode.currentApiLevel;
import static java.util.Collections.list;
public class DeviceUtils {
private static final int MAX_MEMORY_CACHE_SIZE = 30 * 1024 * 1024; // 30 MB
private static final int MIN_DISK_CACHE_SIZE = 30 * 1024 * 1024; // 30 MB
private static final int MAX_DISK_CACHE_SIZE = 100 * 1024 * 1024; // 100 MB
private DeviceUtils() {}
public static enum IP {
IPv4,
IPv6;
private boolean matches(final String address) {
switch (this) {
case IPv4:
return InetAddressUtils.isIPv4Address(address);
case IPv6:
return InetAddressUtils.isIPv6Address(address);
default:
return false;
}
}
private String toString(final String address) {
switch (this) {
case IPv4:
return address;
case IPv6:
return address.split("%")[0];
default:
return null;
}
}
}
public static String getIpAddress(IP ip) throws SocketException {
for (final NetworkInterface networkInterface : list(NetworkInterface.getNetworkInterfaces())) {
for (final InetAddress address : list(networkInterface.getInetAddresses())) {
if (!address.isLoopbackAddress()) {
String hostAddress = address.getHostAddress().toUpperCase(Locale.US);
if (ip.matches(hostAddress)) {
return ip.toString(hostAddress);
}
}
}
}
return null;
}
public static String getHashedUdid(final Context context) {
if (context == null) {
return null;
}
String udid = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
return Utils.sha1(udid);
}
public static boolean isNetworkAvailable(final Context context) {
if (context == null) {
return false;
}
final int internetPermission = context.checkCallingOrSelfPermission(INTERNET);
if (internetPermission == PackageManager.PERMISSION_DENIED) {
return false;
}
/**
* This is only checking if we have permission to access the network state
* It's possible to not have permission to check network state but still be able
* to access the network itself.
*/
final int networkAccessPermission = context.checkCallingOrSelfPermission(ACCESS_NETWORK_STATE);
if (networkAccessPermission == PackageManager.PERMISSION_DENIED) {
return true;
}
// Otherwise, perform the connectivity check.
try {
final ConnectivityManager connnectionManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo networkInfo = connnectionManager.getActiveNetworkInfo();
return networkInfo.isConnected();
} catch (NullPointerException e) {
return false;
}
}
public static int memoryCacheSizeBytes(final Context context) {
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
long memoryClass = activityManager.getMemoryClass();
if (currentApiLevel().isAtLeast(HONEYCOMB)) {
try {
final int flagLargeHeap = ApplicationInfo.class.getDeclaredField("FLAG_LARGE_HEAP").getInt(null);
if (Utils.bitMaskContainsFlag(context.getApplicationInfo().flags, flagLargeHeap)) {
memoryClass = (Integer) new MethodBuilder(activityManager, "getLargeMemoryClass").execute();
}
} catch (Exception e) {
MoPubLog.d("Unable to reflectively determine large heap size on Honeycomb and above.");
}
}
long result = Math.min(MAX_MEMORY_CACHE_SIZE, memoryClass / 8 * 1024 * 1024);
return (int) result;
}
public static long diskCacheSizeBytes(File dir, long minSize) {
long size = minSize;
try {
StatFs statFs = new StatFs(dir.getAbsolutePath());
long availableBytes = ((long) statFs.getBlockCount()) * statFs.getBlockSize();
size = availableBytes / 50;
} catch (IllegalArgumentException e) {
MoPubLog.d("Unable to calculate 2% of available disk space, defaulting to minimum");
}
// Bound inside min/max size for disk cache.
return Math.max(Math.min(size, MAX_DISK_CACHE_SIZE), MIN_DISK_CACHE_SIZE);
}
public static long diskCacheSizeBytes(File dir) {
return diskCacheSizeBytes(dir, MIN_DISK_CACHE_SIZE);
}
public static int getScreenOrientation(@NonNull final Activity activity) {
final int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
final DisplayMetrics displayMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
final int width = displayMetrics.widthPixels;
final int height = displayMetrics.heightPixels;
final boolean isPortrait =
(((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180)) &&
height > width) ||
(((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270)) &&
width > height);
if (isPortrait) {
switch (rotation) {
case Surface.ROTATION_0:
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
case Surface.ROTATION_90:
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
case Surface.ROTATION_180:
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
case Surface.ROTATION_270:
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
default:
MoPubLog.d("Unknown screen orientation. Defaulting to portrait.");
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
}
} else {
switch (rotation) {
case Surface.ROTATION_0:
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
case Surface.ROTATION_90:
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
case Surface.ROTATION_180:
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
case Surface.ROTATION_270:
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
default:
MoPubLog.d("Unknown screen orientation. Defaulting to landscape.");
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
}
}
}
}