/* * Copyright 2011 - AndroidQuery.com (tinyeeliu@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.androidquery.util; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.Thread.UncaughtExceptionHandler; import java.lang.reflect.Method; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import android.app.Application; import android.content.Context; import android.content.SharedPreferences.Editor; import android.content.res.Resources; import android.os.AsyncTask; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.animation.AlphaAnimation; import com.androidquery.AQuery; import com.androidquery.AbstractAQuery.LoadListener; /** * Utility methods. Warning: Methods might changed in future versions. * */ public class AQUtility { private static boolean debug = false; private static Object wait; public static void setDebug(boolean debug) { AQUtility.debug = debug; } public static boolean isDebug() { return debug; } public static void debugWait(long time) { if (!debug) return; if (wait == null) wait = new Object(); synchronized (wait) { try { wait.wait(time); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void debugNotify() { if (!debug || wait == null) return; synchronized (wait) { wait.notifyAll(); } } public static void debug(Object msg) { if (debug) { Log.w("AQuery", msg + ""); } } public static void warn(Object msg, Object msg2) { Log.w("AQuery", msg + ":" + msg2); } public static void debug(Object msg, Object msg2) { if (debug) { Log.w("AQuery", msg + ":" + msg2); } } public static void debug(Throwable e) { if (debug) { String trace = Log.getStackTraceString(e); Log.w("AQuery", trace); } } public static void report(Throwable e) { if (e == null) return; try { // debug(e); warn("reporting", Log.getStackTraceString(e)); if (eh != null) { eh.uncaughtException(Thread.currentThread(), e); } } catch (Exception ex) { ex.printStackTrace(); } } private static UncaughtExceptionHandler eh; public static void setExceptionHandler(UncaughtExceptionHandler handler) { eh = handler; } private static Map<String, Long> times = new HashMap<String, Long>(); public static void time(String tag) { times.put(tag, System.currentTimeMillis()); } public static long timeEnd(String tag, long threshold) { Long old = times.get(tag); if (old == null) return 0; long now = System.currentTimeMillis(); long diff = now - old; if (threshold == 0 || diff > threshold) { debug(tag, diff); } return diff; } public static Object invokeHandler(Object handler, String callback, boolean fallback, boolean report, Class<?>[] cls, Object... params) { return invokeHandler(handler, callback, fallback, report, cls, null, params); } public static Object invokeHandler(Object handler, String callback, boolean fallback, boolean report, Class<?>[] cls, Class<?>[] cls2, Object... params) { try { return invokeMethod(handler, callback, fallback, cls, cls2, params); } catch (Exception e) { if (report) { AQUtility.report(e); } else { AQUtility.debug(e); } return null; } } private static Object invokeMethod(Object handler, String callback, boolean fallback, Class<?>[] cls, Class<?>[] cls2, Object... params) throws Exception { if (handler == null || callback == null) return null; Method method = null; try { if (cls == null) cls = new Class[0]; method = handler.getClass().getMethod(callback, cls); return method.invoke(handler, params); } catch (NoSuchMethodException e) { // AQUtility.debug(e.getMessage()); } try { if (fallback) { if (cls2 == null) { method = handler.getClass().getMethod(callback); return method.invoke(handler); } else { method = handler.getClass().getMethod(callback, cls2); return method.invoke(handler, params); } } } catch (NoSuchMethodException e) { } return null; } public static void transparent(View view, boolean transparent) { float alpha = 1; if (transparent) alpha = 0.5f; setAlpha(view, alpha); } private static void setAlpha(View view, float alphaValue) { if (alphaValue == 1) { view.clearAnimation(); } else { AlphaAnimation alpha = new AlphaAnimation(alphaValue, alphaValue); alpha.setDuration(0); // Make animation instant alpha.setFillAfter(true); // Tell it to persist after the animation // ends view.startAnimation(alpha); } } public static void ensureUIThread() { if (!isUIThread()) { AQUtility.report(new IllegalStateException("Not UI Thread")); } } public static boolean isUIThread() { long uiId = Looper.getMainLooper().getThread().getId(); long cId = Thread.currentThread().getId(); return uiId == cId; } private static Handler handler; public static Handler getHandler() { if (handler == null) { handler = new Handler(Looper.getMainLooper()); } return handler; } public static void post(Runnable run) { getHandler().post(run); } public static void post(Object handler, String method) { post(handler, method, new Class[0]); } public static void post(final Object handler, final String method, final Class<?>[] sig, final Object... params) { post(new Runnable() { @Override public void run() { AQUtility.invokeHandler(handler, method, false, true, sig, params); } }); } public static void postAsync(final Runnable run) { AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { try { run.run(); } catch (Exception e) { AQUtility.report(e); } return null; } }; task.execute(); } public static void postAsync(Object handler, String method) { postAsync(handler, method, new Class[0]); } public static void postAsync(final Object handler, final String method, final Class<?>[] sig, final Object... params) { postAsync(new Runnable() { @Override public void run() { AQUtility.invokeHandler(handler, method, false, true, sig, params); } }); } public static void removePost(Runnable run) { getHandler().removeCallbacks(run); } public static void postDelayed(Runnable run, long delay) { getHandler().postDelayed(run, delay); } public static void apply(Editor editor) { if (AQuery.SDK_INT >= 9) { AQUtility.invokeHandler(editor, "apply", false, true, null, (Object[]) null); } else { editor.commit(); } } public static String getMD5Hex(String str) { byte[] data = getMD5(str.getBytes()); BigInteger bi = new BigInteger(data).abs(); String result = bi.toString(36); return result; } public static byte[] getMD5(byte[] data) { MessageDigest digest; try { digest = java.security.MessageDigest.getInstance("MD5"); digest.update(data); byte[] hash = digest.digest(); return hash; } catch (NoSuchAlgorithmException e) { AQUtility.report(e); } return null; } private static final int IO_BUFFER_SIZE = 1024 * 4; public static void copy(InputStream in, OutputStream out) throws IOException { copy(in, out, 0, null); } public static void copy(InputStream in, OutputStream out, int max, Progress progress) throws IOException { copy(in, out, max, progress, null); } public static void copy(InputStream in, OutputStream out, int max, Progress progress, LoadListener loadListener) throws IOException { if (progress != null) { progress.reset(); progress.setBytes(max); } byte[] b = new byte[IO_BUFFER_SIZE]; int read; int count = max; while ((read = in.read(b)) != -1) { if (loadListener != null) { count = count - read; loadListener.onLoadProgress(count, max); } out.write(b, 0, read); if (progress != null) { progress.increment(read); } } if (progress != null) { progress.done(); } } public static byte[] toBytes(InputStream is) { byte[] result = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { copy(is, baos); result = baos.toByteArray(); } catch (IOException e) { AQUtility.report(e); } close(is); return result; } public static void write(File file, byte[] data) { try { if (!file.exists()) { try { file.createNewFile(); } catch (Exception e) { AQUtility.debug("file create fail", file); AQUtility.report(e); } } FileOutputStream fos = new FileOutputStream(file); fos.write(data); fos.close(); } catch (Exception e) { AQUtility.report(e); } } public static void close(Closeable c) { try { if (c != null) { c.close(); } } catch (Exception e) { } } private static ScheduledExecutorService storeExe; private static ScheduledExecutorService getFileStoreExecutor() { if (storeExe == null) { storeExe = Executors.newSingleThreadScheduledExecutor(); } return storeExe; } public static void storeAsync(File file, byte[] data, long delay) { ScheduledExecutorService exe = getFileStoreExecutor(); Common task = new Common().method(Common.STORE_FILE, file, data); exe.schedule(task, delay, TimeUnit.MILLISECONDS); } private static File cacheDir; private static File pcacheDir; public static File getCacheDir(Context context, int policy) { if (policy == AQuery.CACHE_PERSISTENT) { if (pcacheDir != null) return pcacheDir; File cd = getCacheDir(context); pcacheDir = new File(cd, "persistent"); pcacheDir.mkdirs(); return pcacheDir; } else { return getCacheDir(context); } } public static File getCacheDir(Context context) { if (cacheDir == null) { cacheDir = new File(context.getCacheDir(), "aquery"); cacheDir.mkdirs(); } return cacheDir; } public static void setCacheDir(File dir) { cacheDir = dir; if (cacheDir != null) { cacheDir.mkdirs(); } } private static File makeCacheFile(File dir, String name) { File result = new File(dir, name); return result; } private static String getCacheFileName(String url) { String hash = getMD5Hex(url); return hash; } public static File getCacheFile(File dir, String url) { if (url == null) return null; if (url.startsWith(File.separator)) { return new File(url); } String name = getCacheFileName(url); File file = makeCacheFile(dir, name); return file; } public static File getExistedCacheByUrl(File dir, String url) { File file = getCacheFile(dir, url); if (file == null || !file.exists()) { return null; } return file; } public static File getExistedCacheByUrlSetAccess(File dir, String url) { File file = getExistedCacheByUrl(dir, url); if (file != null) { lastAccess(file); } return file; } private static void lastAccess(File file) { long now = System.currentTimeMillis(); file.setLastModified(now); } public static void store(File file, byte[] data) { try { if (file != null) { AQUtility.write(file, data); } } catch (Exception e) { AQUtility.report(e); } } public static void cleanCacheAsync(Context context) { long triggerSize = 3000000; long targetSize = 2000000; cleanCacheAsync(context, triggerSize, targetSize); } public static void cleanCacheAsync(Context context, long triggerSize, long targetSize) { try { File cacheDir = getCacheDir(context); Common task = new Common().method(Common.CLEAN_CACHE, cacheDir, triggerSize, targetSize); ScheduledExecutorService exe = getFileStoreExecutor(); exe.schedule(task, 0, TimeUnit.MILLISECONDS); } catch (Exception e) { AQUtility.report(e); } } public static void cleanCache(File cacheDir, long triggerSize, long targetSize) { try { File[] files = cacheDir.listFiles(); if (files == null) return; Arrays.sort(files, new Common()); if (testCleanNeeded(files, triggerSize)) { cleanCache(files, targetSize); } File temp = getTempDir(); if (temp != null && temp.exists()) { cleanCache(temp.listFiles(), 0); } } catch (Exception e) { AQUtility.report(e); } } public static File getTempDir() { File ext = Environment.getExternalStorageDirectory(); File tempDir = new File(ext, "aquery/temp"); tempDir.mkdirs(); if (!tempDir.exists() || !tempDir.canWrite()) { return null; } return tempDir; } private static boolean testCleanNeeded(File[] files, long triggerSize) { long total = 0; for (File f : files) { total += f.length(); if (total > triggerSize) { return true; } } return false; } private static void cleanCache(File[] files, long maxSize) { long total = 0; int deletes = 0; for (int i = 0; i < files.length; i++) { File f = files[i]; if (f.isFile()) { total += f.length(); if (total < maxSize) { // ok } else { f.delete(); deletes++; // AQUtility.debug("del", f.getAbsolutePath()); } } } AQUtility.debug("deleted", deletes); } public static int dip2pixel(Context context, float n) { int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, n, context.getResources() .getDisplayMetrics()); return value; } public static float pixel2dip(Context context, float n) { Resources resources = context.getResources(); DisplayMetrics metrics = resources.getDisplayMetrics(); float dp = n / (metrics.densityDpi / 160f); return dp; } private static Context context; public static void setContext(Application app) { context = app.getApplicationContext(); } public static Context getContext() { if (context == null) { AQUtility.warn("warn", "getContext with null"); AQUtility.debug(new IllegalStateException()); } return context; } }