package com.shahul3d.indiasatelliteweather.service;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.Toast;
import com.crashlytics.android.Crashlytics;
import com.noveogroup.android.log.Log;
import com.shahul3d.indiasatelliteweather.R;
import com.shahul3d.indiasatelliteweather.controllers.WeatherApplication;
import com.shahul3d.indiasatelliteweather.data.AppConstants;
import com.shahul3d.indiasatelliteweather.helpers.MAPDownloadBroadcastHelper;
import com.shahul3d.indiasatelliteweather.utils.CrashUtils;
import com.shahul3d.indiasatelliteweather.utils.HttpClient;
import com.shahul3d.indiasatelliteweather.utils.PreferenceUtil;
import com.shahul3d.indiasatelliteweather.utils.StorageUtils;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Response;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import de.greenrobot.event.EventBus;
public class MAPDownloadController {
MAPDownloadBroadcastHelper mapDownloadBroadcastHelper;
Boolean activeDownloadsList[] = new Boolean[AppConstants.MAP_URL.size()];
Context context = WeatherApplication.getContext();
private SharedPreferences preference_General = null;
public MAPDownloadController(EventBus eventBus) {
mapDownloadBroadcastHelper = new MAPDownloadBroadcastHelper(eventBus);
preference_General = WeatherApplication.getContext().getSharedPreferences("BackgroundPreference", Activity.MODE_PRIVATE);
}
public void downloadMAPRequest(int mapID, int mapType) {
Log.d("downloadMAPRequest called");
if (!performDuplicateDownloadCheck(mapID)) {
Log.e("Duplicate download request for the same map type");
return;
}
String mapFileName = AppConstants.getMapType(mapID, mapType);
Log.d("Download initiated for fileName:" + mapFileName + " mapType:" + mapType + " mapID:" + mapID);
//Marking current map type as in progress.
activeDownloadsList[mapID] = true;
//Notifying UI about download is starting, so start rotating the loader..
mapDownloadBroadcastHelper.broadcastDownloadProgress(mapType, mapID, 0);
//Downloading the map.
String URL = AppConstants.getMapURL(mapFileName);
final HashMap<String, Object> downloadResult = downloadMap(URL, mapID, mapType);
if (downloadResult == null || downloadResult.get("map") == null) {
//Download failed
Log.e("Download Failed:" + mapFileName + " mapType:" + mapType + " mapID:" + mapID);
markDownloadComplete(mapType, mapID, false);
return;
}
Log.a("Download Success:" + mapFileName + " mapType:" + mapType + " mapID:" + mapID);
Bitmap downloadedMAP = (Bitmap) downloadResult.get("map");
String lastModifiedHeader = (String) downloadResult.get("lost_modified");
//Trimming the borders of some map types that are not meaningful to the user.
mapDownloadBroadcastHelper.broadcastDownloadProgress(mapType, mapID, 92);
downloadedMAP = removeMapBorders(mapFileName, downloadedMAP);
mapDownloadBroadcastHelper.broadcastDownloadProgress(mapType, mapID, 95);
//Save downloaded image for offline use.
try {
saveDownloadedMap(mapFileName, downloadedMAP);
} catch (Exception e) {
//Store Map failed
Log.e("Storing MAPS failed:" + mapFileName + " mapType:" + mapType + " mapID:" + mapID);
CrashUtils.trackException("Error while storing map on DISK", e);
markDownloadComplete(mapType, mapID, false);
return;
}
//Download & Everything successful.
Log.d("Storing MAPS success:" + mapFileName + " mapType:" + mapType + " mapID:" + mapID);
mapDownloadBroadcastHelper.broadcastDownloadProgress(mapType, mapID, 100);
PreferenceUtil.updateLastModifiedTime(mapFileName, lastModifiedHeader);
markDownloadComplete(mapType, mapID, true);
//check for .nomeida file and create it if it is not available.
StorageUtils.createNoMediaFile();
}
public boolean performDuplicateDownloadCheck(int mapID) {
if (activeDownloadsList[mapID] != null && activeDownloadsList[mapID]) {
return false;
}
return true;
}
public HashMap<String, Object> downloadMap(String URL, int mapID, int mapType) {
Bitmap downloadedBitmap = null;
String lastModifiedHeader = "";
try {
//Invoking Http call to download the URL.
//Calling through synchronous mode, since async wont suits on our requirement.
OkHttpClient httpClient = HttpClient.getInstance();
Call call = httpClient.newCall(HttpClient.generateRequest(URL));
Response response = call.execute();
//These caching headers should be stored on preferences.
lastModifiedHeader = response.header("Last-Modified", "");
Log.d("last modified: " + lastModifiedHeader);
// Log.d("\nN/W counts: " + httpClient.getCache().getNetworkCount() + "\nReq Counts: " + httpClient.getCache().getRequestCount() + "\nCache Hits: " + httpClient.getCache().getHitCount());
if (response.code() == 200) {
InputStream inputStream;
ByteArrayOutputStream outArrrayIPStream;
try {
inputStream = response.body().byteStream();
outArrrayIPStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int statusUpdateTrigger = 0;
long downloaded = 0;
long responseSize = response.body().contentLength();
Log.d("Total file size to download: " + responseSize);
for (int count; (count = inputStream.read(buffer)) != -1; ) {
outArrrayIPStream.write(buffer, 0, count);
downloaded += count;
statusUpdateTrigger++;
// Log.d(String.format("%d / %d", downloaded, responseSize));
if (statusUpdateTrigger > AppConstants.STATUS_UPDATE_THRESHOLD) {
statusUpdateTrigger = 0;
Long downloadedPercent = downloaded * AppConstants.MAX_DOWNLOAD_PROGRESS / responseSize;
Log.d("downloaded percent: " + downloadedPercent);
mapDownloadBroadcastHelper.broadcastDownloadProgress(mapType, mapID, downloadedPercent.intValue());
}
}
byte[] responseImage = outArrrayIPStream.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
downloadedBitmap = BitmapFactory.decodeByteArray(responseImage, 0, responseImage.length, options);
} catch (Exception e) {
CrashUtils.trackException("MAP download IO exception", e);
return null;
}
} else {
CrashUtils.trackException("res code other than 200: " + response.code(), null);
return null;
}
} catch (IOException e) {
e.printStackTrace();
}
final HashMap<String, Object> result = new HashMap<>();
result.put("map", downloadedBitmap);
result.put("lost_modified", lastModifiedHeader);
return result;
}
private Bitmap removeMapBorders(String mapFileName, Bitmap bmp) {
//Try to remove unwanted parts from MAP. return the original MAP in case of any errors.
try {
//Trim the unwanted area from the Ultra Violet Map.
if (mapFileName.equals(AppConstants.MAP_UV) || mapFileName.equals(AppConstants.MAP_HEAT)) {
return Bitmap.createBitmap(bmp, 0, 180, 1250, 1400);
}
} catch (Exception e) {
Crashlytics.log("trim MAP Error");
Crashlytics.setString("MapType", mapFileName);
try {
if (bmp != null) {
Crashlytics.setInt("mapWidth", bmp.getWidth());
Crashlytics.setInt("mapHeight", bmp.getHeight());
}
} catch (Exception e1) {
Crashlytics.logException(e1);
}
Crashlytics.logException(e);
}
return bmp;
}
private void saveDownloadedMap(String mapType, Bitmap bmp) throws Exception {
File temp_file = new File(StorageUtils.getAppSpecificFolder() + File.separator + mapType + "_temp.jpg");
FileOutputStream fileOutStream = new FileOutputStream(temp_file.getPath());
// Compression Quality set to 100. ie. NO COMPRESSION.
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fileOutStream);
fileOutStream.flush();
fileOutStream.close();
boolean success = temp_file.renameTo(new File(StorageUtils.getAppSpecificFolder(), mapType + ".jpg"));
Log.d("Map saved to: " + temp_file.getAbsolutePath() + ". Overwritten? = " + success);
}
public void networkUnavailableHandling(int mapID, int mapType) {
Toast.makeText(context, context.getResources().getString(R.string.no_internet_connection), Toast.LENGTH_SHORT).show();
markDownloadComplete(mapType, mapID, false);
}
public void markDownloadComplete(int mapType, int mapID, boolean status) {
Log.d("Marking Download as complete for mapType:" + mapType + " mapID:" + mapID + " status:" + status);
//Updating the controller flag about the specific map type is no more on progress.
activeDownloadsList[mapID] = false;
mapDownloadBroadcastHelper.broadcastDownloadStatus(mapType, mapID, status);
}
}