/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.linkbubble.adblock; import android.content.Context; import android.content.SharedPreferences; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.Calendar; public class ADBlockUtils { public static final long MILLISECONDS_IN_A_DAY = 86400 * 1000; public static final int BUFFER_TO_READ = 16384; // 16Kb private static final String ETAGS_PREFS_NAME = "EtagsPrefsFile"; private static final String ETAG_NAME = "Etag"; private static final String TIME_NAME = "Time"; public static void saveETagInfo(Context context, String prepend, EtagObject etagObject) { SharedPreferences sharedPref = context.getSharedPreferences(ETAGS_PREFS_NAME, 0); SharedPreferences.Editor editor = sharedPref.edit(); editor.putString(prepend + ETAG_NAME, etagObject.mEtag); editor.putLong(prepend + TIME_NAME, etagObject.mMilliSeconds); editor.apply(); } public static EtagObject getETagInfo(Context context, String prepend) { SharedPreferences sharedPref = context.getSharedPreferences(ETAGS_PREFS_NAME, 0); EtagObject etagObject = new EtagObject(); etagObject.mEtag = sharedPref.getString(prepend + ETAG_NAME, ""); etagObject.mMilliSeconds = sharedPref.getLong(prepend + TIME_NAME, 0); return etagObject; } public static String getDataVerNumber(String url) { String[] split = url.split("/"); if (split.length > 2) { return split[split.length - 2]; } return ""; } public static void removeOldVersionFiles(Context context, String fileName) { File dataDirPath = new File(context.getApplicationInfo().dataDir); File[] fileList = dataDirPath.listFiles(); for (File file : fileList) { if (file.getAbsoluteFile().toString().endsWith(fileName)) { file.delete(); } } } public static byte[] readLocalFile(File path) { byte[] buffer = null; FileInputStream inputStream = null; try { if (!path.exists()) { return null; } inputStream = new FileInputStream(path.getAbsolutePath()); int size = inputStream.available(); buffer = new byte[size]; int n = - 1; int bytesOffset = 0; byte[] tempBuffer = new byte[ADBlockUtils.BUFFER_TO_READ]; while ( (n = inputStream.read(tempBuffer)) != -1) { System.arraycopy(tempBuffer, 0, buffer, bytesOffset, n); bytesOffset += n; } inputStream.close(); } catch (IOException e) { e.printStackTrace(); } return buffer; } public static byte[] readData(Context context, String fileName, String urlString, String eTagPrepend, String verNumber, boolean downloadOnly) { File dataPath = new File(context.getApplicationInfo().dataDir, verNumber + fileName); long oldFileSize = dataPath.length(); EtagObject previousEtag = ADBlockUtils.getETagInfo(context, eTagPrepend); long milliSeconds = Calendar.getInstance().getTimeInMillis(); if (0 == oldFileSize || (milliSeconds - previousEtag.mMilliSeconds >= ADBlockUtils.MILLISECONDS_IN_A_DAY)) { ADBlockUtils.downloadDatFile(context, oldFileSize, previousEtag, milliSeconds, fileName, urlString, eTagPrepend, verNumber); } if (downloadOnly) { return null; } return readLocalFile(dataPath); } public static void downloadDatFile(Context context, long oldFileSize, EtagObject previousEtag, long currentMilliSeconds, String fileName, String urlString, String eTagPrepend, String verNumber) { byte[] buffer = null; InputStream inputStream = null; HttpURLConnection connection = null; try { URL url = new URL(urlString); connection = (HttpURLConnection) url.openConnection(); String etag = connection.getHeaderField("ETag"); int length = connection.getContentLength(); if (null == etag) { etag = ""; } boolean downloadFile = true; if (oldFileSize == length && etag.equals(previousEtag.mEtag)) { downloadFile = false; } previousEtag.mEtag = etag; previousEtag.mMilliSeconds = currentMilliSeconds; ADBlockUtils.saveETagInfo(context, eTagPrepend, previousEtag); if (!downloadFile) { return; } ADBlockUtils.removeOldVersionFiles(context, fileName); connection.connect(); if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { return; } File path = new File(context.getApplicationInfo().dataDir, verNumber + fileName); FileOutputStream outputStream = new FileOutputStream(path); inputStream = connection.getInputStream(); buffer = new byte[ADBlockUtils.BUFFER_TO_READ]; int n = - 1; int totalReadSize = 0; try { while ((n = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, n); totalReadSize += n; } } catch (IllegalStateException exc) { // Sometimes it gives us that exception, found that we should do that way to avoid it: // Each HttpURLConnection instance is used to make a single request but the // underlying network connection to the HTTP server may be transparently shared by other instance. // But we do that way, so just wrapped it for now and we will redownload the file on next request } outputStream.close(); if (length != totalReadSize) { ADBlockUtils.removeOldVersionFiles(context, fileName); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } if (connection != null) connection.disconnect(); } return; } }