package zlc.season.rxdownload2.function; import android.text.TextUtils; import android.util.Log; import org.reactivestreams.Publisher; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.net.ConnectException; import java.net.ProtocolException; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.text.DecimalFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import io.reactivex.Flowable; import io.reactivex.FlowableTransformer; import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.ObservableTransformer; import io.reactivex.disposables.Disposable; import io.reactivex.functions.BiPredicate; import io.reactivex.processors.BehaviorProcessor; import io.reactivex.processors.FlowableProcessor; import okhttp3.internal.http.HttpHeaders; import retrofit2.HttpException; import retrofit2.Response; import zlc.season.rxdownload2.entity.DownloadEvent; import static android.text.TextUtils.concat; import static java.io.File.separator; import static java.lang.String.format; import static java.util.Locale.getDefault; import static java.util.TimeZone.getTimeZone; import static zlc.season.rxdownload2.function.Constant.CACHE; import static zlc.season.rxdownload2.function.Constant.DIR_CREATE_FAILED; import static zlc.season.rxdownload2.function.Constant.DIR_CREATE_SUCCESS; import static zlc.season.rxdownload2.function.Constant.DIR_EXISTS_HINT; import static zlc.season.rxdownload2.function.Constant.DIR_NOT_EXISTS_HINT; import static zlc.season.rxdownload2.function.Constant.FILE_DELETE_FAILED; import static zlc.season.rxdownload2.function.Constant.FILE_DELETE_SUCCESS; import static zlc.season.rxdownload2.function.Constant.LMF_SUFFIX; import static zlc.season.rxdownload2.function.Constant.RETRY_HINT; import static zlc.season.rxdownload2.function.Constant.TAG; import static zlc.season.rxdownload2.function.Constant.TMP_SUFFIX; /** * Author: Season(ssseasonnn@gmail.com) * Date: 2016/11/2 * Time: 09:07 * 工具类 */ public class Utils { private static boolean DEBUG = false; public static void setDebug(boolean flag) { DEBUG = flag; } public static void log(String message) { if (empty(message)) return; if (DEBUG) { Log.i(TAG, message); } } public static void log(String message, Object... args) { log(format(getDefault(), message, args)); } public static void log(Throwable throwable) { Log.w(TAG, throwable); } public static String formatStr(String str, Object... args) { return format(getDefault(), str, args); } public static boolean empty(String string) { return TextUtils.isEmpty(string); } /** * convert long to GMT string * * @param lastModify long * @return String */ public static String longToGMT(long lastModify) { Date d = new Date(lastModify); SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); sdf.setTimeZone(getTimeZone("GMT")); return sdf.format(d); } /** * convert GMT string to long * * @param GMT String * @return long * @throws ParseException */ public static long GMTToLong(String GMT) throws ParseException { if (GMT == null || "".equals(GMT)) { return new Date().getTime(); } SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); sdf.setTimeZone(getTimeZone("GMT")); Date date = sdf.parse(GMT); return date.getTime(); } public static void close(Closeable closeable) throws IOException { if (closeable != null) { closeable.close(); } } public static void closeQuietly(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (RuntimeException rethrown) { throw rethrown; } catch (Exception ignored) { } } } public static FlowableProcessor<DownloadEvent> createProcessor( String missionId, Map<String, FlowableProcessor<DownloadEvent>> processorMap) { if (processorMap.get(missionId) == null) { FlowableProcessor<DownloadEvent> processor = BehaviorProcessor.<DownloadEvent>create().toSerialized(); processorMap.put(missionId, processor); } return processorMap.get(missionId); } public static <U> ObservableTransformer<U, U> retry(final String hint, final int retryCount) { return new ObservableTransformer<U, U>() { @Override public ObservableSource<U> apply(Observable<U> upstream) { return upstream.retry(new BiPredicate<Integer, Throwable>() { @Override public boolean test(Integer integer, Throwable throwable) throws Exception { return retry(hint, retryCount, integer, throwable); } }); } }; } public static <U> FlowableTransformer<U, U> retry2(final String hint, final int retryCount) { return new FlowableTransformer<U, U>() { @Override public Publisher<U> apply(Flowable<U> upstream) { return upstream.retry(new BiPredicate<Integer, Throwable>() { @Override public boolean test(Integer integer, Throwable throwable) throws Exception { return retry(hint, retryCount, integer, throwable); } }); } }; } public static void dispose(Disposable disposable) { if (disposable != null && !disposable.isDisposed()) { disposable.dispose(); } } public static String lastModify(Response<?> response) { return response.headers().get("Last-Modified"); } public static long contentLength(Response<?> response) { return HttpHeaders.contentLength(response.headers()); } public static String fileName(String url, Response<?> response) { String fileName = contentDisposition(response); if (empty(fileName)) { fileName = url.substring(url.lastIndexOf('/') + 1); } if (fileName.startsWith("\"")) { fileName = fileName.substring(1); } if (fileName.endsWith("\"")) { fileName = fileName.substring(0, fileName.length() - 1); } return fileName; } public static String contentDisposition(Response<?> response) { String disposition = response.headers().get("Content-Disposition"); if (empty(disposition)) { return ""; } Matcher m = Pattern.compile(".*filename=(.*)").matcher(disposition.toLowerCase()); if (m.find()) { return m.group(1); } else { return ""; } } public static boolean isChunked(Response<?> response) { return "chunked".equals(transferEncoding(response)); } public static boolean notSupportRange(Response<?> response) { return (TextUtils.isEmpty(contentRange(response)) && !TextUtils.equals(acceptRanges(response), "bytes")) || contentLength(response) == -1 || isChunked(response); } /** * Format file size to String * * @param size long * @return String */ public static String formatSize(long size) { String hrSize; double b = size; double k = size / 1024.0; double m = ((size / 1024.0) / 1024.0); double g = (((size / 1024.0) / 1024.0) / 1024.0); double t = ((((size / 1024.0) / 1024.0) / 1024.0) / 1024.0); DecimalFormat dec = new DecimalFormat("0.00"); if (t > 1) { hrSize = dec.format(t).concat(" TB"); } else if (g > 1) { hrSize = dec.format(g).concat(" GB"); } else if (m > 1) { hrSize = dec.format(m).concat(" MB"); } else if (k > 1) { hrSize = dec.format(k).concat(" KB"); } else { hrSize = dec.format(b).concat(" B"); } return hrSize; } public static Boolean retry(String hint, int maxRetryCount, Integer integer, Throwable throwable) { if (throwable instanceof ProtocolException) { if (integer < maxRetryCount + 1) { log(RETRY_HINT, hint, "ProtocolException", integer); return true; } return false; } else if (throwable instanceof UnknownHostException) { if (integer < maxRetryCount + 1) { log(RETRY_HINT, hint, "UnknownHostException", integer); return true; } return false; } else if (throwable instanceof HttpException) { if (integer < maxRetryCount + 1) { log(RETRY_HINT, hint, "HttpException", integer); return true; } return false; } else if (throwable instanceof SocketTimeoutException) { if (integer < maxRetryCount + 1) { log(RETRY_HINT, hint, "SocketTimeoutException", integer); return true; } return false; } else if (throwable instanceof ConnectException) { if (integer < maxRetryCount + 1) { log(RETRY_HINT, hint, "ConnectException", integer); return true; } return false; } else if (throwable instanceof SocketException) { if (integer < maxRetryCount + 1) { log(RETRY_HINT, hint, "SocketException", integer); return true; } return false; } else { return false; } } /** * return file paths * * @param saveName saveName * @param savePath savePath * @return filePath, tempPath, lmfPath */ public static String[] getPaths(String saveName, String savePath) { String cachePath = concat(savePath, separator, CACHE).toString(); String filePath = concat(savePath, separator, saveName).toString(); String tempPath = concat(cachePath, separator, saveName, TMP_SUFFIX).toString(); String lmfPath = concat(cachePath, separator, saveName, LMF_SUFFIX).toString(); return new String[]{filePath, tempPath, lmfPath}; } /** * return files * * @param saveName saveName * @param savePath savePath * @return file, tempFile, lmfFile */ public static File[] getFiles(String saveName, String savePath) { String[] paths = getPaths(saveName, savePath); return new File[]{new File(paths[0]), new File(paths[1]), new File(paths[2])}; } /** * create dirs with params path * * @param paths paths */ public static void mkdirs(String... paths) { for (String each : paths) { File file = new File(each); if (file.exists() && file.isDirectory()) { log(DIR_EXISTS_HINT, each); } else { log(DIR_NOT_EXISTS_HINT, each); boolean flag = file.mkdirs(); if (flag) { log(DIR_CREATE_SUCCESS, each); } else { log(DIR_CREATE_FAILED, each); } } } } /** * delete files * * @param files files */ public static void deleteFiles(File... files) { for (File each : files) { if (each.exists()) { boolean flag = each.delete(); if (flag) { log(format(getDefault(), FILE_DELETE_SUCCESS, each.getName())); } else { log(format(getDefault(), FILE_DELETE_FAILED, each.getName())); } } } } private static String transferEncoding(Response<?> response) { return response.headers().get("Transfer-Encoding"); } private static String contentRange(Response<?> response) { return response.headers().get("Content-Range"); } private static String acceptRanges(Response<?> response) { return response.headers().get("Accept-Ranges"); } }