package de.tum.in.tumcampusapp.auxiliary;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.widget.ImageView;
import com.google.common.base.Optional;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import de.tum.in.tumcampusapp.api.Helper;
import de.tum.in.tumcampusapp.managers.CacheManager;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class NetUtils {
private final Context mContext;
private final CacheManager cacheManager;
private final OkHttpClient client;
public NetUtils(Context context) {
//Manager caches all requests
mContext = context;
cacheManager = new CacheManager(mContext);
//Set our max wait time for each request
client = Helper.getOkClient(context);
}
public static Optional<JSONObject> downloadJson(Context context, String url) {
return new NetUtils(context).downloadJson(url);
}
/**
* Check if a network connection is available or can be available soon
*
* @return true if available
*/
public static boolean isConnected(Context con) {
ConnectivityManager cm = (ConnectivityManager) con
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
return netInfo != null && netInfo.isConnectedOrConnecting();
}
/**
* Check if a network connection is available or can be available soon
* and if the available connection is a mobile internet connection
*
* @return true if available
*/
public static boolean isConnectedMobileData(Context con) {
ConnectivityManager cm = (ConnectivityManager) con
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
return netInfo != null && netInfo.isConnectedOrConnecting() && netInfo.getType() == ConnectivityManager.TYPE_MOBILE;
}
/**
* Check if a network connection is available or can be available soon
* and if the available connection is a wifi internet connection
*
* @return true if available
*/
public static boolean isConnectedWifi(Context con) {
ConnectivityManager cm = (ConnectivityManager) con.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
return netInfo != null && netInfo.isConnectedOrConnecting() && netInfo.getType() == ConnectivityManager.TYPE_WIFI;
}
private Optional<ResponseBody> getOkHttpResponse(String url) throws IOException {
// if we are not online, fetch makes no sense
boolean isOnline = isConnected(mContext);
if (!isOnline || url == null) {
return Optional.absent();
}
Utils.logv("Download URL: " + url);
Request.Builder builder = new Request.Builder().url(url);
//Execute the request
Response res = client.newCall(builder.build()).execute();
return Optional.of(res.body());
}
/**
* Downloads the content of a HTTP URL as String
*
* @param url Download URL location
* @return The content string
* @throws IOException
*/
public Optional<String> downloadStringHttp(String url) throws IOException {
Optional<ResponseBody> body = getOkHttpResponse(url);
if (body.isPresent()) {
return Optional.of(body.get().string());
}
return Optional.absent();
}
public Optional<String> downloadStringAndCache(String url, int validity, boolean force) {
try {
Optional<String> content;
if (!force) {
content = cacheManager.getFromCache(url);
if (content.isPresent()) {
return content;
}
}
content = downloadStringHttp(url);
if (content.isPresent()) {
cacheManager.addToCache(url, content.get(), validity, CacheManager.CACHE_TYP_DATA);
return content;
}
return Optional.absent();
} catch (IOException e) {
Utils.log(e);
return Optional.absent();
}
}
/**
* Download a file in the same thread.
* If file already exists the method returns immediately
* without downloading anything
*
* @param url Download location
* @param target Target filename in local file system
* @throws IOException When the download failed
*/
public void downloadToFile(String url, String target) throws IOException {
File f = new File(target);
if (f.exists()) {
return;
}
File file = new File(target);
FileOutputStream out = new FileOutputStream(file);
try {
Optional<ResponseBody> body = getOkHttpResponse(url);
if (!body.isPresent()) {
file.delete();
throw new IOException();
}
byte[] buffer = body.get().bytes();
out.write(buffer, 0, buffer.length);
out.flush();
} finally {
out.close();
}
}
/**
* Downloads an image synchronously from the given url
*
* @param pUrl Image url
* @return Downloaded image as {@link Bitmap}
*/
public Optional<File> downloadImage(String pUrl) {
try {
String url = pUrl.replaceAll(" ", "%20");
Optional<String> file = cacheManager.getFromCache(url);
if (file.isPresent()) {
File result = new File(file.get());
// TODO: remove this check when #391 is fixed
// The cache could have been cleaned manually, so we need an existence check
if (result.exists()) {
return Optional.of(result);
}
}
file = Optional.of(mContext.getCacheDir().getAbsolutePath() + '/' + Utils.md5(url) + ".jpg");
File f = new File(file.get());
downloadToFile(url, file.get());
// At this point, we are certain, that the file really has been downloaded and can safely be added to the cache
cacheManager.addToCache(url, file.get(), CacheManager.VALIDITY_TEN_DAYS, CacheManager.CACHE_TYP_IMAGE);
return Optional.of(f);
} catch (IOException e) {
Utils.log(e, pUrl);
return Optional.absent();
}
}
/**
* Downloads an image synchronously from the given url
*
* @param url Image url
* @return Downloaded image as {@link Bitmap}
*/
public Optional<Bitmap> downloadImageToBitmap(@NonNull String url) {
Optional<File> f = downloadImage(url);
if (f.isPresent()) {
return Optional.fromNullable(BitmapFactory.decodeFile(f.get().getAbsolutePath()));
}
return Optional.absent();
}
/**
* Download an image in background and sets the image to the image view
*
* @param url URL
* @param imageView Image
*/
public void loadAndSetImage(final String url, final ImageView imageView) {
synchronized (CacheManager.BITMAP_CACHE) {
Bitmap bmp = CacheManager.BITMAP_CACHE.get(url);
if (bmp != null) {
imageView.setImageBitmap(bmp);
return;
}
}
new AsyncTask<Void, Void, Optional<Bitmap>>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
CacheManager.IMAGE_VIEWS.put(imageView, url);
imageView.setImageBitmap(null);
}
@Override
protected Optional<Bitmap> doInBackground(Void... voids) {
return downloadImageToBitmap(url);
}
@Override
protected void onPostExecute(Optional<Bitmap> bitmap) {
if (!bitmap.isPresent()) {
return;
}
synchronized (CacheManager.BITMAP_CACHE) {
CacheManager.BITMAP_CACHE.put(url, bitmap.get());
}
String tag = CacheManager.IMAGE_VIEWS.get(imageView);
if (tag != null && tag.equals(url)) {
imageView.setImageBitmap(bitmap.get());
}
}
}.execute();
}
/**
* Download a JSON stream from a URL
*
* @param url Valid URL
* @return JSONObject
*/
public Optional<JSONObject> downloadJson(String url) {
try {
Optional<String> data = downloadStringHttp(url);
if (data.isPresent()) {
Utils.logv("downloadJson " + data);
return Optional.of(new JSONObject(data.get()));
}
} catch (IOException | JSONException e) {
Utils.log(e);
}
return Optional.absent();
}
/**
* Download a JSON stream from a URL or load it from cache
*
* @param url Valid URL
* @param force Load data anyway and fill cache, even if valid cached version exists
* @return JSONObject
*/
public Optional<JSONArray> downloadJsonArray(String url, int validity, boolean force) {
Optional<String> download = downloadStringAndCache(url, validity, force);
JSONArray result = null;
if (download.isPresent()) {
try {
result = new JSONArray(download.get());
} catch (JSONException e) {
Utils.log(e);
}
}
return Optional.fromNullable(result);
}
/**
* Download a JSON stream from a URL or load it from cache
*
* @param url Valid URL
* @param force Load data anyway and fill cache, even if valid cached version exists
* @return JSONObject
*/
public Optional<JSONObject> downloadJsonObject(String url, int validity, boolean force) {
Optional<String> download = downloadStringAndCache(url, validity, force);
JSONObject result = null;
if (download.isPresent()) {
try {
result = new JSONObject(download.get());
} catch (JSONException e) {
Utils.log(e);
}
}
return Optional.fromNullable(result);
}
}