package me.devsaki.hentoid.util; import android.content.Context; import android.content.res.AssetManager; import android.net.Uri; import android.os.AsyncTask; import com.thin.downloadmanager.DownloadManager; import com.thin.downloadmanager.DownloadRequest; import com.thin.downloadmanager.DownloadStatusListenerV1; import com.thin.downloadmanager.ThinDownloadManager; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import me.devsaki.hentoid.HentoidApp; /** * Created by avluis on 07/22/2016. * Assets Cache Management Util */ public class AssetsCache { private static final String TAG = LogHelper.makeLogTag(AssetsCache.class); private static final String CACHE_JSON = "https://raw.githubusercontent.com/AVnetWS/Hentoid/master/.cache/cache.json"; private static final String CACHE_PACK = "cache.zip"; private static final String KEY_PACK_URL = "packURL"; private static final String KEY_VERSION_CODE = "versionCode"; // TODO: Revert cache version before publishing app update (same goes for cache.json) private static final int BUNDLED_CACHE_VERSION = 3; private static AssetManager assetManager; private static File cacheDir; public static void init(Context cxt) { assetManager = cxt.getAssets(); cacheDir = cxt.getExternalCacheDir(); if (cacheDir != null) { // Check remote cache version checkNetworkConnectivity(); } else { LogHelper.d(TAG, "Cache INIT Failed!"); } } private static void checkNetworkConnectivity() { AsyncTask.execute(() -> { boolean connected = NetworkStatus.hasInternetAccess(HentoidApp.getAppContext()); if (connected) { LogHelper.d(TAG, "Checking remote cache version."); new UpdateCheckTask().execute(CACHE_JSON); } else { LogHelper.w(TAG, "Network is not connected!"); unpackBundle(); } }); } private static void downloadCachePack(String downloadURL) { // Clean up cache directory LogHelper.d(TAG, "Directory cleaned successfully: " + FileHelper.cleanDirectory(cacheDir)); // Download cache pack Uri downloadUri = Uri.parse(downloadURL); final Uri destinationUri = Uri.parse(cacheDir + "/" + CACHE_PACK); DownloadRequest request = new DownloadRequest(downloadUri) .setDestinationURI(destinationUri) .setPriority(DownloadRequest.Priority.HIGH) .setStatusListener(new DownloadStatusListenerV1() { @Override public void onDownloadComplete(DownloadRequest downloadRequest) { // Unpack cache file File file = new File(String.valueOf(destinationUri)); LogHelper.d(TAG, "Downloaded cache file: " + file.getAbsolutePath()); extractFile(file); } @Override public void onDownloadFailed(DownloadRequest downloadRequest, int errorCode, String errorMessage) { unpackBundle(); } @Override public void onProgress(DownloadRequest downloadRequest, long totalBytes, long downloadedBytes, int progress) { // Not listening } }); DownloadManager downloadManager = new ThinDownloadManager(); LogHelper.d(TAG, "Download Request ID: " + downloadManager.add(request)); } private static void unpackBundle() { InputStream inputStream; File file; try { inputStream = assetManager.open(CACHE_PACK); file = new File(cacheDir + "/" + CACHE_PACK); OutputStream outputStream = new FileOutputStream(file); byte buffer[] = new byte[1024]; int length; while ((length = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } outputStream.close(); inputStream.close(); extractFile(file); } catch (IOException e) { LogHelper.e(TAG, e, "Failed to assemble file from assets"); } } private static void extractFile(File file) { LogHelper.d(TAG, "Extracting cache files."); String zipFile = file.getAbsolutePath(); String destinationPath = cacheDir.getPath(); new ZipUtil.UnZipTask().execute(zipFile, destinationPath); } private static class UpdateCheckTask extends AsyncTask<String, Void, Void> { int remoteCacheVersion = -1; String downloadURL; @Override protected Void doInBackground(String... params) { try { JSONObject jsonObject = new JsonHelper().jsonReader(params[0]); if (jsonObject != null) { remoteCacheVersion = jsonObject.getInt(KEY_VERSION_CODE); downloadURL = jsonObject.getString(KEY_PACK_URL); } else { LogHelper.w(TAG, "JSON response was null!"); unpackBundle(); } } catch (IOException e) { LogHelper.e(TAG, e, "IO ERROR"); unpackBundle(); } catch (JSONException e) { LogHelper.e(TAG, e, "Error with JSON File"); unpackBundle(); } return null; } @Override protected void onPostExecute(Void aVoid) { LogHelper.d(TAG, "Remote cache version: " + remoteCacheVersion); if (remoteCacheVersion >= 1) { if (BUNDLED_CACHE_VERSION < remoteCacheVersion) { LogHelper.d(TAG, "Bundled cache is outdated."); downloadCachePack(downloadURL); } else { LogHelper.d(TAG, "Bundled cache is current or newer."); unpackBundle(); } } } } }