diff --git a/src/com/hippo/ehviewer/BeautifyScreen.java b/src/com/hippo/ehviewer/BeautifyScreen.java index f3d01921c..13c516473 100644 --- a/src/com/hippo/ehviewer/BeautifyScreen.java +++ b/src/com/hippo/ehviewer/BeautifyScreen.java @@ -1,111 +1,111 @@ -package com.hippo.ehviewer; - -import com.hippo.ehviewer.util.Ui; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.res.Resources; -import android.os.Build; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.Gravity; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.widget.FrameLayout.LayoutParams; - -@SuppressLint("NewApi") -public class BeautifyScreen { - private static final String TAG = "BeautifyScreen"; - private static Context mContext; - private static int mStatusBarHeight = 0; - private static int mNavigationBarHeight = 0; - - private static int sbbId = 0; - private static int nbbId = 1; - - private BeautifyScreen(){} - - public static void init(Context context) { - mContext = context; - if (Build.VERSION.SDK_INT >= 19) { - Resources resources = context.getResources(); - int sbhResourceId = resources.getIdentifier("status_bar_height", - "dimen", "android"); - if (sbhResourceId > 0) - mStatusBarHeight = resources - .getDimensionPixelSize(sbhResourceId); - int nbhResourceId = resources.getIdentifier( - "navigation_bar_height", "dimen", "android"); - if (nbhResourceId > 0) - mNavigationBarHeight = resources - .getDimensionPixelSize(nbhResourceId); - } - } - - public static void ColourfyScreen(Activity activity) { - if (Build.VERSION.SDK_INT >= 19) { - Resources resources = activity.getResources(); - Window win = activity.getWindow(); - - WindowManager.LayoutParams winParams = win.getAttributes(); - winParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS - | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; - win.setAttributes(winParams); - - ViewGroup decorViewGroup = (ViewGroup) win.getDecorView(); - // Add status bar background - if (mStatusBarHeight > 0) { - View statusBarView = new View(mContext); - LayoutParams params1 = new LayoutParams( - LayoutParams.MATCH_PARENT, mStatusBarHeight); - params1.gravity = Gravity.TOP; - statusBarView.setLayoutParams(params1); - statusBarView.setBackgroundColor(resources - .getColor(R.color.blue_dark)); - statusBarView.setId(sbbId); - decorViewGroup.addView(statusBarView); - } - - // Add navigation bar background - if (Ui.hasNavigationBar() && mNavigationBarHeight > 0 && - isPortrait(activity)) { - View navigationBarView = new View(mContext); - LayoutParams params2 = new LayoutParams( - LayoutParams.MATCH_PARENT, mNavigationBarHeight); - params2.gravity = Gravity.BOTTOM; - navigationBarView.setLayoutParams(params2); - navigationBarView.setBackgroundColor(resources - .getColor(R.color.blue_dark)); - navigationBarView.setId(nbbId); - decorViewGroup.addView(navigationBarView); - } - } - } - - private static boolean isPortrait(Activity activity) { - DisplayMetrics dm = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(dm); - return dm.heightPixels > dm.widthPixels; - } - - public static void fixColour(Activity activity) { - if (Build.VERSION.SDK_INT < 19) - return; - Window win = activity.getWindow(); - ViewGroup decorViewGroup = (ViewGroup) win.getDecorView(); - View navigationBarView = decorViewGroup.findViewById(nbbId); - if (navigationBarView == null) - return; - if (!isPortrait(activity)) - navigationBarView.setVisibility(View.GONE); - else - navigationBarView.setVisibility(View.VISIBLE); - } -} +package com.hippo.ehviewer; + +import com.hippo.ehviewer.util.Ui; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.Resources; +import android.os.Build; +import android.util.DisplayMetrics; +import com.hippo.ehviewer.util.Log; +import android.view.Gravity; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout.LayoutParams; + +@SuppressLint("NewApi") +public class BeautifyScreen { + private static final String TAG = "BeautifyScreen"; + private static Context mContext; + private static int mStatusBarHeight = 0; + private static int mNavigationBarHeight = 0; + + private static int sbbId = 0; + private static int nbbId = 1; + + private BeautifyScreen(){} + + public static void init(Context context) { + mContext = context; + if (Build.VERSION.SDK_INT >= 19) { + Resources resources = context.getResources(); + int sbhResourceId = resources.getIdentifier("status_bar_height", + "dimen", "android"); + if (sbhResourceId > 0) + mStatusBarHeight = resources + .getDimensionPixelSize(sbhResourceId); + int nbhResourceId = resources.getIdentifier( + "navigation_bar_height", "dimen", "android"); + if (nbhResourceId > 0) + mNavigationBarHeight = resources + .getDimensionPixelSize(nbhResourceId); + } + } + + public static void ColourfyScreen(Activity activity) { + if (Build.VERSION.SDK_INT >= 19) { + Resources resources = activity.getResources(); + Window win = activity.getWindow(); + + WindowManager.LayoutParams winParams = win.getAttributes(); + winParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; + win.setAttributes(winParams); + + ViewGroup decorViewGroup = (ViewGroup) win.getDecorView(); + // Add status bar background + if (mStatusBarHeight > 0) { + View statusBarView = new View(mContext); + LayoutParams params1 = new LayoutParams( + LayoutParams.MATCH_PARENT, mStatusBarHeight); + params1.gravity = Gravity.TOP; + statusBarView.setLayoutParams(params1); + statusBarView.setBackgroundColor(resources + .getColor(R.color.blue_dark)); + statusBarView.setId(sbbId); + decorViewGroup.addView(statusBarView); + } + + // Add navigation bar background + if (Ui.hasNavigationBar() && mNavigationBarHeight > 0 && + isPortrait(activity)) { + View navigationBarView = new View(mContext); + LayoutParams params2 = new LayoutParams( + LayoutParams.MATCH_PARENT, mNavigationBarHeight); + params2.gravity = Gravity.BOTTOM; + navigationBarView.setLayoutParams(params2); + navigationBarView.setBackgroundColor(resources + .getColor(R.color.blue_dark)); + navigationBarView.setId(nbbId); + decorViewGroup.addView(navigationBarView); + } + } + } + + private static boolean isPortrait(Activity activity) { + DisplayMetrics dm = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(dm); + return dm.heightPixels > dm.widthPixels; + } + + public static void fixColour(Activity activity) { + if (Build.VERSION.SDK_INT < 19) + return; + Window win = activity.getWindow(); + ViewGroup decorViewGroup = (ViewGroup) win.getDecorView(); + View navigationBarView = decorViewGroup.findViewById(nbbId); + if (navigationBarView == null) + return; + if (!isPortrait(activity)) + navigationBarView.setVisibility(View.GONE); + else + navigationBarView.setVisibility(View.VISIBLE); + } +} diff --git a/src/com/hippo/ehviewer/DiskCache.java b/src/com/hippo/ehviewer/DiskCache.java index 304928d0f..6c85c6ca5 100644 --- a/src/com/hippo/ehviewer/DiskCache.java +++ b/src/com/hippo/ehviewer/DiskCache.java @@ -1,306 +1,306 @@ -package com.hippo.ehviewer; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import com.hippo.ehviewer.util.Cache; -import com.hippo.ehviewer.util.Ui; -import com.hippo.ehviewer.util.Util; -import com.jakewharton.disklrucache.DiskLruCache; - -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Movie; -import android.os.Environment; -import android.util.Log; - -// For Gallery cover key is gid, -// for example , gid is 618395, token is 0439fa3666, -// so key is 618395 - -// For Gallery preview key is gid-preview-num-row, -// for example , gid is 618395, token is 0439fa3666, page2 -// so key is 618395-preview-2-0 - -// For Gallery image key is gid-preview-num, -// for example , gid is 618395, token is 0439fa3666, image2 -// so key is 618395-image-2 - -public class DiskCache { - private static String TAG = "ImageDiskCache"; - - private static final int VALUE_IDX = 0; - - private Context mContext; - private BitmapFactory.Options opt; - private final DiskLruCache diskLruCache; - - public DiskCache(Context context, String path, long maxSize) throws NameNotFoundException, IOException { - this.mContext = context; - - opt = Ui.getBitmapOpt(); - if (!Cache.hasSdCard()) { - throw new IllegalStateException("Has no SdCard."); - } - - File dir = new File(Environment.getExternalStorageDirectory() + path); - int version = mContext.getPackageManager().getPackageInfo( - mContext.getPackageName(), 0).versionCode; - version = 1; - diskLruCache = DiskLruCache.open(dir, version, 1, maxSize); - } - - public long size() { - return diskLruCache.size(); - } - - public long maxSize() { - return diskLruCache.getMaxSize(); - } - - public void setMaxSize(long maxSize) { - diskLruCache.setMaxSize(maxSize); - } - - public void close() { - try { - diskLruCache.close(); - } catch (IOException e) { - Log.d(TAG, "diskLruCache close error !"); - } - } - - public boolean hasKey(String key) { - DiskLruCache.Snapshot snapshot = null; - try { - snapshot = diskLruCache.get(key); - } catch (IOException e) { - } - if(snapshot==null) - return false; - snapshot.close(); - return true; - } - - public Object get(String key, int type) { - DiskLruCache.Snapshot snapshot = null; - try { - snapshot = diskLruCache.get(key); - } catch (IOException e) { - } - if (snapshot == null) - return null; - InputStream is = snapshot.getInputStream(VALUE_IDX); - if (type == Util.BITMAP) { - Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt); - return bitmap; - } else if (type == Util.MOVIE) { - is = new BufferedInputStream(is, 16 * 1024); - is.mark(16 * 1024); - Movie movie = Movie.decodeStream(is); - return movie; - } - return null; - } - - public boolean put(String key, InputStream is) throws IOException { - DiskLruCache.Editor editor = diskLruCache.edit(key); - if (editor == null) - return false; - BufferedOutputStream bos = new BufferedOutputStream(editor.newOutputStream(VALUE_IDX)); - OutputStream os = new CacheOutputStream(bos, editor); - Util.copy(is, os); - return true; - } - - public void clear() { - try { - diskLruCache.delete(); - } catch (IOException e) { - } - } - - private class CacheOutputStream extends FilterOutputStream { - - private final DiskLruCache.Editor editor; - private boolean failed = false; - - private CacheOutputStream(OutputStream os, DiskLruCache.Editor editor) { - super(os); - this.editor = editor; - } - - @Override - public void close() throws IOException { - IOException closeException = null; - try { - super.close(); - } catch (IOException e) { - closeException = e; - } - - if (failed) { - editor.abort(); - } else { - editor.commit(); - } - - if (closeException != null) throw closeException; - } - - @Override - public void flush() throws IOException { - try { - super.flush(); - } catch (IOException e) { - failed = true; - throw e; - } - } - - @Override - public void write(int oneByte) throws IOException { - try { - super.write(oneByte); - } catch (IOException e) { - failed = true; - throw e; - } - } - - @Override - public void write(byte[] buffer) throws IOException { - try { - super.write(buffer); - } catch (IOException e) { - failed = true; - throw e; - } - } - - @Override - public void write(byte[] buffer, int offset, int length) throws IOException { - try { - super.write(buffer, offset, length); - } catch (IOException e) { - failed = true; - throw e; - } - } - } - /* - private Context context = null; - private File dir = null; - int maxSize = 1024 * 10; - - public DiskCache(Context context, String path, int maxSize) { - this.context = context; - this.maxSize = maxSize; - if (maxSize <= 0) - maxSize = 1024 * 10; - - File rootdir = Environment.getExternalStorageDirectory(); - dir = new File(rootdir + path); - dir.mkdirs(); - } - - public boolean hasKey(String key) { - synchronized (key) { - - File file = new File(dir, key); - if (file.exists()) { - if (file.isDirectory()) - file.delete(); - else - return true; - } - return false; - } - } - - public Object get(String key, int type) { - synchronized (key) { - File file = new File(dir, key); - if (!file.isFile()) - return null; - try { - InputStream is = new FileInputStream(file); - if (type == Util.BITMAP) { - Bitmap bitmap = BitmapFactory.decodeStream(is, null, Util.opt); - return bitmap; - } else if (type == Util.MOVIE) { - is = new BufferedInputStream(is, 16 * 1024); - is.mark(16 * 1024); - Movie movie = Movie.decodeStream(is); - return movie; - } - } catch (FileNotFoundException e) { - Log.d(TAG, "WTF, I have checked that the file does exists."); - e.printStackTrace(); - } - return null; - } - } - - public boolean put(String key, InputStream is) throws IOException { - synchronized (key) { - File file = new File(dir, key); - try { - file.delete(); - file.createNewFile(); - } catch (IOException e) { - dir.mkdirs(); - file.delete(); - try { - file.createNewFile(); - } catch (IOException e1) { - Log.d(TAG, "WTF, mkdirs didn't work? Path is " + file.getPath()); - e1.printStackTrace(); - return false; - } - } - try { - Util.inputStream2File(is, file); - return true; - } catch (IOException e) { - Log.d(TAG, "Put " + key + " error."); - throw e; - } - } - } - - public void clear() { - clearDirectory(dir); - } - - private void clearDirectory(File dir) { - - for (File file: dir.listFiles()) { - if (file.isDirectory()) clearDirectory(file); - file.delete(); - } - - }*/ - /* - * private static String getStingMD5(String s) { String re = null; try { - * MessageDigest messageDigest =MessageDigest.getInstance(Algorithm); byte[] - * inputByteArray = s.getBytes(); messageDigest.update(inputByteArray); - * byte[] resultByteArray = messageDigest.digest(); re = - * byteArrayToHex(resultByteArray); } catch (NoSuchAlgorithmException e) { - * e.printStackTrace(); Log.d(TAG, e.getMessage()); } return re; } - * - * private static String byteArrayToHex(byte[] byteArray) { char[] hexDigits - * = {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' }; - * char[] resultCharArray =new char[byteArray.length * 2]; int index = 0; - * for (byte b : byteArray) { resultCharArray[index++] = hexDigits[b>>> 4 & - * 0xf]; resultCharArray[index++] = hexDigits[b& 0xf]; } return new - * String(resultCharArray); } - */ -} +package com.hippo.ehviewer; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.hippo.ehviewer.util.Cache; +import com.hippo.ehviewer.util.Ui; +import com.hippo.ehviewer.util.Util; +import com.jakewharton.disklrucache.DiskLruCache; + +import android.content.Context; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Movie; +import android.os.Environment; +import com.hippo.ehviewer.util.Log; + +// For Gallery cover key is gid, +// for example , gid is 618395, token is 0439fa3666, +// so key is 618395 + +// For Gallery preview key is gid-preview-num-row, +// for example , gid is 618395, token is 0439fa3666, page2 +// so key is 618395-preview-2-0 + +// For Gallery image key is gid-preview-num, +// for example , gid is 618395, token is 0439fa3666, image2 +// so key is 618395-image-2 + +public class DiskCache { + private static String TAG = "ImageDiskCache"; + + private static final int VALUE_IDX = 0; + + private Context mContext; + private BitmapFactory.Options opt; + private final DiskLruCache diskLruCache; + + public DiskCache(Context context, String path, long maxSize) throws NameNotFoundException, IOException { + this.mContext = context; + + opt = Ui.getBitmapOpt(); + if (!Cache.hasSdCard()) { + throw new IllegalStateException("Has no SdCard."); + } + + File dir = new File(Environment.getExternalStorageDirectory() + path); + int version = mContext.getPackageManager().getPackageInfo( + mContext.getPackageName(), 0).versionCode; + version = 1; + diskLruCache = DiskLruCache.open(dir, version, 1, maxSize); + } + + public long size() { + return diskLruCache.size(); + } + + public long maxSize() { + return diskLruCache.getMaxSize(); + } + + public void setMaxSize(long maxSize) { + diskLruCache.setMaxSize(maxSize); + } + + public void close() { + try { + diskLruCache.close(); + } catch (IOException e) { + Log.d(TAG, "diskLruCache close error !"); + } + } + + public boolean hasKey(String key) { + DiskLruCache.Snapshot snapshot = null; + try { + snapshot = diskLruCache.get(key); + } catch (IOException e) { + } + if(snapshot==null) + return false; + snapshot.close(); + return true; + } + + public Object get(String key, int type) { + DiskLruCache.Snapshot snapshot = null; + try { + snapshot = diskLruCache.get(key); + } catch (IOException e) { + } + if (snapshot == null) + return null; + InputStream is = snapshot.getInputStream(VALUE_IDX); + if (type == Util.BITMAP) { + Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt); + return bitmap; + } else if (type == Util.MOVIE) { + is = new BufferedInputStream(is, 16 * 1024); + is.mark(16 * 1024); + Movie movie = Movie.decodeStream(is); + return movie; + } + return null; + } + + public boolean put(String key, InputStream is) throws IOException { + DiskLruCache.Editor editor = diskLruCache.edit(key); + if (editor == null) + return false; + BufferedOutputStream bos = new BufferedOutputStream(editor.newOutputStream(VALUE_IDX)); + OutputStream os = new CacheOutputStream(bos, editor); + Util.copy(is, os); + return true; + } + + public void clear() { + try { + diskLruCache.delete(); + } catch (IOException e) { + } + } + + private class CacheOutputStream extends FilterOutputStream { + + private final DiskLruCache.Editor editor; + private boolean failed = false; + + private CacheOutputStream(OutputStream os, DiskLruCache.Editor editor) { + super(os); + this.editor = editor; + } + + @Override + public void close() throws IOException { + IOException closeException = null; + try { + super.close(); + } catch (IOException e) { + closeException = e; + } + + if (failed) { + editor.abort(); + } else { + editor.commit(); + } + + if (closeException != null) throw closeException; + } + + @Override + public void flush() throws IOException { + try { + super.flush(); + } catch (IOException e) { + failed = true; + throw e; + } + } + + @Override + public void write(int oneByte) throws IOException { + try { + super.write(oneByte); + } catch (IOException e) { + failed = true; + throw e; + } + } + + @Override + public void write(byte[] buffer) throws IOException { + try { + super.write(buffer); + } catch (IOException e) { + failed = true; + throw e; + } + } + + @Override + public void write(byte[] buffer, int offset, int length) throws IOException { + try { + super.write(buffer, offset, length); + } catch (IOException e) { + failed = true; + throw e; + } + } + } + /* + private Context context = null; + private File dir = null; + int maxSize = 1024 * 10; + + public DiskCache(Context context, String path, int maxSize) { + this.context = context; + this.maxSize = maxSize; + if (maxSize <= 0) + maxSize = 1024 * 10; + + File rootdir = Environment.getExternalStorageDirectory(); + dir = new File(rootdir + path); + dir.mkdirs(); + } + + public boolean hasKey(String key) { + synchronized (key) { + + File file = new File(dir, key); + if (file.exists()) { + if (file.isDirectory()) + file.delete(); + else + return true; + } + return false; + } + } + + public Object get(String key, int type) { + synchronized (key) { + File file = new File(dir, key); + if (!file.isFile()) + return null; + try { + InputStream is = new FileInputStream(file); + if (type == Util.BITMAP) { + Bitmap bitmap = BitmapFactory.decodeStream(is, null, Util.opt); + return bitmap; + } else if (type == Util.MOVIE) { + is = new BufferedInputStream(is, 16 * 1024); + is.mark(16 * 1024); + Movie movie = Movie.decodeStream(is); + return movie; + } + } catch (FileNotFoundException e) { + Log.d(TAG, "WTF, I have checked that the file does exists."); + e.printStackTrace(); + } + return null; + } + } + + public boolean put(String key, InputStream is) throws IOException { + synchronized (key) { + File file = new File(dir, key); + try { + file.delete(); + file.createNewFile(); + } catch (IOException e) { + dir.mkdirs(); + file.delete(); + try { + file.createNewFile(); + } catch (IOException e1) { + Log.d(TAG, "WTF, mkdirs didn't work? Path is " + file.getPath()); + e1.printStackTrace(); + return false; + } + } + try { + Util.inputStream2File(is, file); + return true; + } catch (IOException e) { + Log.d(TAG, "Put " + key + " error."); + throw e; + } + } + } + + public void clear() { + clearDirectory(dir); + } + + private void clearDirectory(File dir) { + + for (File file: dir.listFiles()) { + if (file.isDirectory()) clearDirectory(file); + file.delete(); + } + + }*/ + /* + * private static String getStingMD5(String s) { String re = null; try { + * MessageDigest messageDigest =MessageDigest.getInstance(Algorithm); byte[] + * inputByteArray = s.getBytes(); messageDigest.update(inputByteArray); + * byte[] resultByteArray = messageDigest.digest(); re = + * byteArrayToHex(resultByteArray); } catch (NoSuchAlgorithmException e) { + * e.printStackTrace(); Log.d(TAG, e.getMessage()); } return re; } + * + * private static String byteArrayToHex(byte[] byteArray) { char[] hexDigits + * = {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' }; + * char[] resultCharArray =new char[byteArray.length * 2]; int index = 0; + * for (byte b : byteArray) { resultCharArray[index++] = hexDigits[b>>> 4 & + * 0xf]; resultCharArray[index++] = hexDigits[b& 0xf]; } return new + * String(resultCharArray); } + */ +} diff --git a/src/com/hippo/ehviewer/ImageLoadManager.java b/src/com/hippo/ehviewer/ImageLoadManager.java index f628923f0..416710a18 100644 --- a/src/com/hippo/ehviewer/ImageLoadManager.java +++ b/src/com/hippo/ehviewer/ImageLoadManager.java @@ -12,7 +12,7 @@ import android.graphics.Bitmap; import android.os.Handler; import android.os.Message; import android.support.v4.util.LruCache; -import android.util.Log; +import com.hippo.ehviewer.util.Log; public class ImageLoadManager { private static final String TAG = "ImageLoadManager"; diff --git a/src/com/hippo/ehviewer/activity/DownloadActivity.java b/src/com/hippo/ehviewer/activity/DownloadActivity.java index fa859b978..b8b2ffa5f 100644 --- a/src/com/hippo/ehviewer/activity/DownloadActivity.java +++ b/src/com/hippo/ehviewer/activity/DownloadActivity.java @@ -33,7 +33,7 @@ import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; import android.os.IBinder; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; diff --git a/src/com/hippo/ehviewer/activity/FavouriteActivity.java b/src/com/hippo/ehviewer/activity/FavouriteActivity.java index 863400621..808f55899 100644 --- a/src/com/hippo/ehviewer/activity/FavouriteActivity.java +++ b/src/com/hippo/ehviewer/activity/FavouriteActivity.java @@ -8,7 +8,7 @@ import android.content.Intent; import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; diff --git a/src/com/hippo/ehviewer/activity/MangaActivity.java b/src/com/hippo/ehviewer/activity/MangaActivity.java index 3cee4bda6..5d873bb38 100644 --- a/src/com/hippo/ehviewer/activity/MangaActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaActivity.java @@ -37,7 +37,7 @@ import android.os.Build; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.Window; diff --git a/src/com/hippo/ehviewer/activity/MangaDetailActivity.java b/src/com/hippo/ehviewer/activity/MangaDetailActivity.java index 149b85852..868c5460b 100644 --- a/src/com/hippo/ehviewer/activity/MangaDetailActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaDetailActivity.java @@ -33,7 +33,7 @@ import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.os.Bundle; import android.util.DisplayMetrics; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; diff --git a/src/com/hippo/ehviewer/activity/MangaDownloadActivity.java b/src/com/hippo/ehviewer/activity/MangaDownloadActivity.java index c82a8234e..e94a7b793 100644 --- a/src/com/hippo/ehviewer/activity/MangaDownloadActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaDownloadActivity.java @@ -30,7 +30,7 @@ import android.os.Environment; import android.os.Handler; import android.os.Message; import android.support.v4.view.PagerAdapter; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; diff --git a/src/com/hippo/ehviewer/gallery/GalleryView.java b/src/com/hippo/ehviewer/gallery/GalleryView.java index cdde4459a..df923e465 100644 --- a/src/com/hippo/ehviewer/gallery/GalleryView.java +++ b/src/com/hippo/ehviewer/gallery/GalleryView.java @@ -6,7 +6,7 @@ import android.graphics.Color; import android.graphics.Movie; import android.graphics.Rect; import android.graphics.RectF; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.MotionEvent; import com.hippo.ehviewer.R; diff --git a/src/com/hippo/ehviewer/gallery/common/Utils.java b/src/com/hippo/ehviewer/gallery/common/Utils.java index 517dc408d..3fc4f0fc4 100644 --- a/src/com/hippo/ehviewer/gallery/common/Utils.java +++ b/src/com/hippo/ehviewer/gallery/common/Utils.java @@ -23,7 +23,7 @@ import android.database.Cursor; import android.os.Build; import android.os.ParcelFileDescriptor; import android.text.TextUtils; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import java.io.Closeable; import java.io.IOException; diff --git a/src/com/hippo/ehviewer/gallery/data/ImageSet.java b/src/com/hippo/ehviewer/gallery/data/ImageSet.java index 54098dffd..ae8a2d251 100644 --- a/src/com/hippo/ehviewer/gallery/data/ImageSet.java +++ b/src/com/hippo/ehviewer/gallery/data/ImageSet.java @@ -18,7 +18,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Movie; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.util.SparseArray; // TODO 初期建立一个线程检索文件夹中所有文件以寻找到所有图片文件 diff --git a/src/com/hippo/ehviewer/gallery/glrenderer/BasicTexture.java b/src/com/hippo/ehviewer/gallery/glrenderer/BasicTexture.java index 5933d7b94..63cdf31a1 100644 --- a/src/com/hippo/ehviewer/gallery/glrenderer/BasicTexture.java +++ b/src/com/hippo/ehviewer/gallery/glrenderer/BasicTexture.java @@ -17,7 +17,7 @@ package com.hippo.ehviewer.gallery.glrenderer; import android.graphics.RectF; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.gallery.common.Utils; diff --git a/src/com/hippo/ehviewer/gallery/glrenderer/GLES11Canvas.java b/src/com/hippo/ehviewer/gallery/glrenderer/GLES11Canvas.java index 4e987a102..240e86d3d 100644 --- a/src/com/hippo/ehviewer/gallery/glrenderer/GLES11Canvas.java +++ b/src/com/hippo/ehviewer/gallery/glrenderer/GLES11Canvas.java @@ -22,7 +22,7 @@ import android.graphics.RectF; import android.opengl.GLU; import android.opengl.GLUtils; import android.opengl.Matrix; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.gallery.common.Utils; import com.hippo.ehviewer.util.IntArray; diff --git a/src/com/hippo/ehviewer/gallery/glrenderer/GLES20Canvas.java b/src/com/hippo/ehviewer/gallery/glrenderer/GLES20Canvas.java index fa711ecb1..a963bdb81 100644 --- a/src/com/hippo/ehviewer/gallery/glrenderer/GLES20Canvas.java +++ b/src/com/hippo/ehviewer/gallery/glrenderer/GLES20Canvas.java @@ -21,7 +21,7 @@ import android.graphics.RectF; import android.opengl.GLES20; import android.opengl.GLUtils; import android.opengl.Matrix; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.util.IntArray; diff --git a/src/com/hippo/ehviewer/gallery/glrenderer/MovieTexture.java b/src/com/hippo/ehviewer/gallery/glrenderer/MovieTexture.java index 96761a8f4..a8f8cd568 100644 --- a/src/com/hippo/ehviewer/gallery/glrenderer/MovieTexture.java +++ b/src/com/hippo/ehviewer/gallery/glrenderer/MovieTexture.java @@ -4,7 +4,7 @@ import junit.framework.Assert; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Movie; -import android.util.Log; +import com.hippo.ehviewer.util.Log; public class MovieTexture extends CanvasTexture { private static final int DEFAULT_MOVIE_DURATION = 1000; diff --git a/src/com/hippo/ehviewer/gallery/glrenderer/RawTexture.java b/src/com/hippo/ehviewer/gallery/glrenderer/RawTexture.java index 7a6495ef3..665df0a40 100644 --- a/src/com/hippo/ehviewer/gallery/glrenderer/RawTexture.java +++ b/src/com/hippo/ehviewer/gallery/glrenderer/RawTexture.java @@ -16,7 +16,7 @@ package com.hippo.ehviewer.gallery.glrenderer; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import javax.microedition.khronos.opengles.GL11; diff --git a/src/com/hippo/ehviewer/gallery/glrenderer/UploadedTexture.java b/src/com/hippo/ehviewer/gallery/glrenderer/UploadedTexture.java index 661f13256..ba54e9d71 100644 --- a/src/com/hippo/ehviewer/gallery/glrenderer/UploadedTexture.java +++ b/src/com/hippo/ehviewer/gallery/glrenderer/UploadedTexture.java @@ -19,7 +19,7 @@ package com.hippo.ehviewer.gallery.glrenderer; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.opengl.GLUtils; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import junit.framework.Assert; import java.util.HashMap; diff --git a/src/com/hippo/ehviewer/gallery/ui/GLRootView.java b/src/com/hippo/ehviewer/gallery/ui/GLRootView.java index 716cae4b6..52c332d36 100644 --- a/src/com/hippo/ehviewer/gallery/ui/GLRootView.java +++ b/src/com/hippo/ehviewer/gallery/ui/GLRootView.java @@ -26,7 +26,7 @@ import android.os.Build; import android.os.Process; import android.os.SystemClock; import android.util.AttributeSet; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; diff --git a/src/com/hippo/ehviewer/gallery/ui/GLView.java b/src/com/hippo/ehviewer/gallery/ui/GLView.java index 8c23bc95d..ae8fc8267 100644 --- a/src/com/hippo/ehviewer/gallery/ui/GLView.java +++ b/src/com/hippo/ehviewer/gallery/ui/GLView.java @@ -19,7 +19,7 @@ package com.hippo.ehviewer.gallery.ui; import android.annotation.SuppressLint; import android.graphics.Rect; import android.os.SystemClock; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.MotionEvent; import com.hippo.ehviewer.gallery.anim.CanvasAnimation; diff --git a/src/com/hippo/ehviewer/gallery/util/GalleryUtils.java b/src/com/hippo/ehviewer/gallery/util/GalleryUtils.java index 6e580a42a..0b560593b 100644 --- a/src/com/hippo/ehviewer/gallery/util/GalleryUtils.java +++ b/src/com/hippo/ehviewer/gallery/util/GalleryUtils.java @@ -27,7 +27,7 @@ import android.os.Environment; import android.os.StatFs; import android.provider.MediaStore; import android.util.DisplayMetrics; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.WindowManager; import com.hippo.ehviewer.util.ThreadPool.CancelListener; diff --git a/src/com/hippo/ehviewer/network/Downloader.java b/src/com/hippo/ehviewer/network/Downloader.java index 98ddfa488..87b476121 100644 --- a/src/com/hippo/ehviewer/network/Downloader.java +++ b/src/com/hippo/ehviewer/network/Downloader.java @@ -15,7 +15,7 @@ import java.net.UnknownHostException; import org.apache.http.conn.ConnectTimeoutException; import android.content.Context; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.R; import com.hippo.ehviewer.exception.FileException; diff --git a/src/com/hippo/ehviewer/network/HttpHelper.java b/src/com/hippo/ehviewer/network/HttpHelper.java index 435f6a26f..68f07c772 100644 --- a/src/com/hippo/ehviewer/network/HttpHelper.java +++ b/src/com/hippo/ehviewer/network/HttpHelper.java @@ -27,7 +27,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.support.v4.util.LruCache; -import android.util.Log; +import com.hippo.ehviewer.util.Log; /** * It is not thread safe diff --git a/src/com/hippo/ehviewer/service/DownloadService.java b/src/com/hippo/ehviewer/service/DownloadService.java index 1b3db318f..137d6cf0b 100644 --- a/src/com/hippo/ehviewer/service/DownloadService.java +++ b/src/com/hippo/ehviewer/service/DownloadService.java @@ -19,7 +19,7 @@ import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.support.v4.app.NotificationCompat; -import android.util.Log; +import com.hippo.ehviewer.util.Log; public class DownloadService extends Service { private static final int DOWNLOAD_NOTIFY_ID = -1; diff --git a/src/com/hippo/ehviewer/util/Cache.java b/src/com/hippo/ehviewer/util/Cache.java index ac8dcda06..8ade04ead 100644 --- a/src/com/hippo/ehviewer/util/Cache.java +++ b/src/com/hippo/ehviewer/util/Cache.java @@ -6,7 +6,7 @@ import android.graphics.Bitmap; import android.os.Build; import android.os.Environment; import android.support.v4.util.LruCache; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.DiskCache; import com.hippo.ehviewer.MangaDetail; diff --git a/src/com/hippo/ehviewer/util/Crash.java b/src/com/hippo/ehviewer/util/Crash.java index 74d314523..4ffa7ee91 100644 --- a/src/com/hippo/ehviewer/util/Crash.java +++ b/src/com/hippo/ehviewer/util/Crash.java @@ -1,196 +1,196 @@ -package com.hippo.ehviewer.util; - -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Build; -import android.os.Environment; -import android.util.Log; - -public class Crash { - private static final String TAG = "Crash"; - - private static Context mContext; - - private static String externalCrashFilePath = "/EhViewer/crash"; - private static String internalCrashFilePath = "/crash"; - - private static final String NEW_CRAHS = "new_crash"; - private static final String LAST_CRASH_POSITION = "last_crash_position"; - private static final String LAST_CRASH_NAME = "last_crash_name"; - - private static DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); - - private static boolean mInit = false; - - /** - * Init Crash - * - * @param context Application context - */ - public static void init(Context context) { - if (mInit) - return; - mInit = true; - - mContext = context; - } - - /** - * Is init - * @return True if init - */ - public static boolean isInit() { - return mInit; - } - - /** - * Save throwable infomation to file - * - * @param ex The throwable to store - */ - public static void saveCrashInfo2File(Throwable ex) { - StringBuffer sb = new StringBuffer(); - collectDeviceInfo(sb); - - Writer writer = new StringWriter(); - PrintWriter printWriter = new PrintWriter(writer); - ex.printStackTrace(printWriter); - Throwable cause = ex.getCause(); - while (cause != null) { - cause.printStackTrace(printWriter); - cause = cause.getCause(); - } - printWriter.close(); - String result = writer.toString(); - Log.e(TAG, result); - sb.append("======== CrashInfo ========\n"); - sb.append(result); - try { - long timestamp = System.currentTimeMillis(); - String time = formatter.format(new Date()); - String fileName = "crash-" + time + "-" + timestamp + ".log"; - String path = null; - boolean position = false; - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - path = Environment.getExternalStorageDirectory() + externalCrashFilePath; - position = true; - } - else { - path = mContext.getFilesDir() + internalCrashFilePath; - position = false; - } - File dir = new File(path); - if (!dir.exists()) { - dir.mkdirs(); - } - FileOutputStream fos = new FileOutputStream(new File(path, fileName)); - fos.write(sb.toString().getBytes()); - fos.close(); - // Record info for next time upload - SharedPreferences configPre = mContext.getSharedPreferences("config", 0); - SharedPreferences.Editor editor = configPre.edit(); - editor.putBoolean(NEW_CRAHS, true); - editor.putBoolean(LAST_CRASH_POSITION, position); - editor.putString(LAST_CRASH_NAME, fileName); - editor.commit(); - } catch (Exception e) { - Log.e(TAG, "An error occured while writing crash file...", e); - } - } - - private static void collectDeviceInfo(StringBuffer sb) { - try { - PackageManager pm = mContext.getPackageManager(); - PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES); - if (pi != null) { - String versionName = pi.versionName == null ? "null" : pi.versionName; - String versionCode = String.valueOf(pi.versionCode); - sb.append("======== PackageInfo ========\n"); - sb.append("PackageName=" + pi.packageName + "\n"); - sb.append("VersionName=" + versionName + "\n"); - sb.append("VersionCode=" + versionCode + "\n"); - sb.append("\n"); - } - } catch (NameNotFoundException e) { - Log.e(TAG, "an error occured when collect package info", e); - } - sb.append("======== DeviceInfo ========\n"); - sb.append("BOARD=" + Build.BOARD + "\n"); - sb.append("BOOTLOADER=" + Build.BOOTLOADER + "\n"); - sb.append("CPU_ABI=" + Build.CPU_ABI + "\n"); - sb.append("CPU_ABI2=" + Build.CPU_ABI2 + "\n"); - sb.append("DEVICE=" + Build.DEVICE + "\n"); - sb.append("DISPLAY=" + Build.DISPLAY + "\n"); - sb.append("FINGERPRINT=" + Build.FINGERPRINT + "\n"); - sb.append("HARDWARE=" + Build.HARDWARE + "\n"); - sb.append("HOST=" + Build.HOST + "\n"); - sb.append("ID=" + Build.ID + "\n"); - sb.append("MANUFACTURER=" + Build.MANUFACTURER + "\n"); - sb.append("MODEL=" + Build.MODEL + "\n"); - sb.append("PRODUCT=" + Build.PRODUCT + "\n"); - sb.append("RADIO=" + Build.getRadioVersion() + "\n"); - sb.append("SERIAL=" + Build.SERIAL + "\n"); - sb.append("TAGS=" + Build.TAGS + "\n"); - sb.append("TYPE=" + Build.TYPE + "\n"); - sb.append("USER=" + Build.USER + "\n"); - sb.append("CODENAME=" + Build.VERSION.CODENAME + "\n"); - sb.append("INCREMENTAL=" + Build.VERSION.INCREMENTAL + "\n"); - sb.append("RELEASE=" + Build.VERSION.RELEASE + "\n"); - sb.append("SDK=" + Build.VERSION.SDK_INT + "\n"); - sb.append("\n"); - } - - /** - * Check is there last crash - * - * @return Return the crash String or null if there is no - */ - public static String getLastCrash() { - SharedPreferences configPre = mContext.getSharedPreferences("config", 0); - if (!configPre.getBoolean(NEW_CRAHS, false)) - return null; - - boolean position = configPre.getBoolean(LAST_CRASH_POSITION, false); - String lastCrashName; - if ((lastCrashName = configPre.getString(LAST_CRASH_NAME, null)) == null) - return null; - - File lastCrashFile; - if (position) { - if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) - return null; - lastCrashFile = new File(Environment.getExternalStorageDirectory() + externalCrashFilePath, lastCrashName); - } - else { - lastCrashFile = new File(mContext.getFilesDir() + internalCrashFilePath, lastCrashName); - } - if (!lastCrashFile.isFile()) - return null; - - try { - byte[] buffer = new byte[(int) lastCrashFile.length()]; - DataInputStream din = new DataInputStream(new FileInputStream(lastCrashFile)); - din.readFully(buffer); - din.close(); - configPre.edit().putBoolean(NEW_CRAHS, false).commit(); - return new String(buffer); - } catch (Exception e) { - Log.e(TAG, "An error occured while reading crash file...", e); - } - return null; - } -} +package com.hippo.ehviewer.util; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Build; +import android.os.Environment; +import com.hippo.ehviewer.util.Log; + +public class Crash { + private static final String TAG = "Crash"; + + private static Context mContext; + + private static String externalCrashFilePath = "/EhViewer/crash"; + private static String internalCrashFilePath = "/crash"; + + private static final String NEW_CRAHS = "new_crash"; + private static final String LAST_CRASH_POSITION = "last_crash_position"; + private static final String LAST_CRASH_NAME = "last_crash_name"; + + private static DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + + private static boolean mInit = false; + + /** + * Init Crash + * + * @param context Application context + */ + public static void init(Context context) { + if (mInit) + return; + mInit = true; + + mContext = context; + } + + /** + * Is init + * @return True if init + */ + public static boolean isInit() { + return mInit; + } + + /** + * Save throwable infomation to file + * + * @param ex The throwable to store + */ + public static void saveCrashInfo2File(Throwable ex) { + StringBuffer sb = new StringBuffer(); + collectDeviceInfo(sb); + + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); + } + printWriter.close(); + String result = writer.toString(); + Log.e(TAG, result); + sb.append("======== CrashInfo ========\n"); + sb.append(result); + try { + long timestamp = System.currentTimeMillis(); + String time = formatter.format(new Date()); + String fileName = "crash-" + time + "-" + timestamp + ".log"; + String path = null; + boolean position = false; + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + path = Environment.getExternalStorageDirectory() + externalCrashFilePath; + position = true; + } + else { + path = mContext.getFilesDir() + internalCrashFilePath; + position = false; + } + File dir = new File(path); + if (!dir.exists()) { + dir.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(new File(path, fileName)); + fos.write(sb.toString().getBytes()); + fos.close(); + // Record info for next time upload + SharedPreferences configPre = mContext.getSharedPreferences("config", 0); + SharedPreferences.Editor editor = configPre.edit(); + editor.putBoolean(NEW_CRAHS, true); + editor.putBoolean(LAST_CRASH_POSITION, position); + editor.putString(LAST_CRASH_NAME, fileName); + editor.commit(); + } catch (Exception e) { + Log.e(TAG, "An error occured while writing crash file...", e); + } + } + + private static void collectDeviceInfo(StringBuffer sb) { + try { + PackageManager pm = mContext.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES); + if (pi != null) { + String versionName = pi.versionName == null ? "null" : pi.versionName; + String versionCode = String.valueOf(pi.versionCode); + sb.append("======== PackageInfo ========\n"); + sb.append("PackageName=" + pi.packageName + "\n"); + sb.append("VersionName=" + versionName + "\n"); + sb.append("VersionCode=" + versionCode + "\n"); + sb.append("\n"); + } + } catch (NameNotFoundException e) { + Log.e(TAG, "an error occured when collect package info", e); + } + sb.append("======== DeviceInfo ========\n"); + sb.append("BOARD=" + Build.BOARD + "\n"); + sb.append("BOOTLOADER=" + Build.BOOTLOADER + "\n"); + sb.append("CPU_ABI=" + Build.CPU_ABI + "\n"); + sb.append("CPU_ABI2=" + Build.CPU_ABI2 + "\n"); + sb.append("DEVICE=" + Build.DEVICE + "\n"); + sb.append("DISPLAY=" + Build.DISPLAY + "\n"); + sb.append("FINGERPRINT=" + Build.FINGERPRINT + "\n"); + sb.append("HARDWARE=" + Build.HARDWARE + "\n"); + sb.append("HOST=" + Build.HOST + "\n"); + sb.append("ID=" + Build.ID + "\n"); + sb.append("MANUFACTURER=" + Build.MANUFACTURER + "\n"); + sb.append("MODEL=" + Build.MODEL + "\n"); + sb.append("PRODUCT=" + Build.PRODUCT + "\n"); + sb.append("RADIO=" + Build.getRadioVersion() + "\n"); + sb.append("SERIAL=" + Build.SERIAL + "\n"); + sb.append("TAGS=" + Build.TAGS + "\n"); + sb.append("TYPE=" + Build.TYPE + "\n"); + sb.append("USER=" + Build.USER + "\n"); + sb.append("CODENAME=" + Build.VERSION.CODENAME + "\n"); + sb.append("INCREMENTAL=" + Build.VERSION.INCREMENTAL + "\n"); + sb.append("RELEASE=" + Build.VERSION.RELEASE + "\n"); + sb.append("SDK=" + Build.VERSION.SDK_INT + "\n"); + sb.append("\n"); + } + + /** + * Check is there last crash + * + * @return Return the crash String or null if there is no + */ + public static String getLastCrash() { + SharedPreferences configPre = mContext.getSharedPreferences("config", 0); + if (!configPre.getBoolean(NEW_CRAHS, false)) + return null; + + boolean position = configPre.getBoolean(LAST_CRASH_POSITION, false); + String lastCrashName; + if ((lastCrashName = configPre.getString(LAST_CRASH_NAME, null)) == null) + return null; + + File lastCrashFile; + if (position) { + if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) + return null; + lastCrashFile = new File(Environment.getExternalStorageDirectory() + externalCrashFilePath, lastCrashName); + } + else { + lastCrashFile = new File(mContext.getFilesDir() + internalCrashFilePath, lastCrashName); + } + if (!lastCrashFile.isFile()) + return null; + + try { + byte[] buffer = new byte[(int) lastCrashFile.length()]; + DataInputStream din = new DataInputStream(new FileInputStream(lastCrashFile)); + din.readFully(buffer); + din.close(); + configPre.edit().putBoolean(NEW_CRAHS, false).commit(); + return new String(buffer); + } catch (Exception e) { + Log.e(TAG, "An error occured while reading crash file...", e); + } + return null; + } +} diff --git a/src/com/hippo/ehviewer/util/EhClient.java b/src/com/hippo/ehviewer/util/EhClient.java index a779cd859..eb267b49d 100644 --- a/src/com/hippo/ehviewer/util/EhClient.java +++ b/src/com/hippo/ehviewer/util/EhClient.java @@ -43,7 +43,7 @@ import android.graphics.Movie; import android.os.Handler; import android.os.Message; import android.support.v4.util.LruCache; -import android.util.Log; +import com.hippo.ehviewer.util.Log; // TODO Stringbuffer to StringBuild diff --git a/src/com/hippo/ehviewer/util/Log.java b/src/com/hippo/ehviewer/util/Log.java new file mode 100644 index 000000000..cb0c0b763 --- /dev/null +++ b/src/com/hippo/ehviewer/util/Log.java @@ -0,0 +1,59 @@ +package com.hippo.ehviewer.util; + +public class Log { + private static final String NULL = "null"; + + public static int v(String tag, String msg) { + if (msg == null) + msg = NULL; + return android.util.Log.v(tag, msg); + } + public static int v(String tag, String msg, Throwable tr) { + if (msg == null) + msg = NULL; + return android.util.Log.v(tag, msg, tr); + } + public static int d(String tag, String msg) { + if (msg == null) + msg = NULL; + return android.util.Log.d(tag, msg); + } + public static int d(String tag, String msg, Throwable tr) { + if (msg == null) + msg = NULL; + return android.util.Log.d(tag, msg, tr); + } + public static int i(String tag, String msg) { + if (msg == null) + msg = NULL; + return android.util.Log.i(tag, msg); + } + public static int i(String tag, String msg, Throwable tr) { + if (msg == null) + msg = NULL; + return android.util.Log.i(tag, msg, tr); + } + public static int w(String tag, String msg) { + if (msg == null) + msg = NULL; + return android.util.Log.w(tag, msg); + } + public static int w(String tag, String msg, Throwable tr) { + if (msg == null) + msg = NULL; + return android.util.Log.w(tag, msg, tr); + } + public static int w(String tag, Throwable tr) { + return android.util.Log.w(tag, tr); + } + public static int e(String tag, String msg) { + if (msg == null) + msg = NULL; + return android.util.Log.e(tag, msg); + } + public static int e(String tag, String msg, Throwable tr) { + if (msg == null) + msg = NULL; + return android.util.Log.e(tag, msg, tr); + } +} diff --git a/src/com/hippo/ehviewer/util/ThreadPool.java b/src/com/hippo/ehviewer/util/ThreadPool.java index cd18591e5..0f1b41d9e 100644 --- a/src/com/hippo/ehviewer/util/ThreadPool.java +++ b/src/com/hippo/ehviewer/util/ThreadPool.java @@ -16,7 +16,7 @@ package com.hippo.ehviewer.util; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; diff --git a/src/com/hippo/ehviewer/view/GetPaddingRelativeLayout.java b/src/com/hippo/ehviewer/view/GetPaddingRelativeLayout.java index 888a0703c..24827c978 100644 --- a/src/com/hippo/ehviewer/view/GetPaddingRelativeLayout.java +++ b/src/com/hippo/ehviewer/view/GetPaddingRelativeLayout.java @@ -3,7 +3,7 @@ package com.hippo.ehviewer.view; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.View; import android.widget.RelativeLayout; diff --git a/src/com/hippo/ehviewer/view/OlImageView.java b/src/com/hippo/ehviewer/view/OlImageView.java index e949334f1..bc932a2ff 100644 --- a/src/com/hippo/ehviewer/view/OlImageView.java +++ b/src/com/hippo/ehviewer/view/OlImageView.java @@ -9,7 +9,7 @@ import android.graphics.Bitmap; import android.graphics.Movie; import android.support.v4.util.LruCache; import android.util.AttributeSet; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.View; public class OlImageView extends SuperImageView { diff --git a/src/com/hippo/ehviewer/view/SuperImageView.java b/src/com/hippo/ehviewer/view/SuperImageView.java index 02d9de04a..1da34bdb4 100644 --- a/src/com/hippo/ehviewer/view/SuperImageView.java +++ b/src/com/hippo/ehviewer/view/SuperImageView.java @@ -1,1509 +1,1509 @@ -package com.hippo.ehviewer.view; - -import android.annotation.SuppressLint; -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.Matrix; -import android.graphics.Movie; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.RectF; -import android.graphics.Xfermode; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Build; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.view.ViewDebug; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; -import android.widget.RemoteViews.RemoteView; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; - -import com.hippo.ehviewer.R; - -// TODO use native to improve gif - -/** - * Displays an arbitrary image, such as an icon. The ImageView class can load - * images from various sources (such as resources or content providers), takes - * care of computing its measurement from the image so that it can be used in - * any layout manager, and provides various display options such as scaling and - * tinting. - * - * @attr ref android.R.styleable#ImageView_adjustViewBounds - * @attr ref android.R.styleable#ImageView_src - * @attr ref android.R.styleable#ImageView_maxWidth - * @attr ref android.R.styleable#ImageView_maxHeight - * @attr ref android.R.styleable#ImageView_tint - * @attr ref android.R.styleable#ImageView_scaleType - * @attr ref android.R.styleable#ImageView_cropToPadding - */ -@RemoteView -public class SuperImageView extends View { - private static String TAG = "SuperImageView"; - // for gif - private Movie mMovie = null; - // Not 0 mean the same timer - private long mMovieStart = 1; - private int mCurrentAnimationTime = 0; - - private static final int DEFAULT_MOVIEW_DURATION = 1000; - - // settable by the client - private Uri mUri; - private int mResource = 0; - private Matrix mMatrix; - private ScaleType mScaleType; - private boolean mHaveFrame = false; - private boolean mAdjustViewBounds = false; - private int mMaxWidth = Integer.MAX_VALUE; - private int mMaxHeight = Integer.MAX_VALUE; - - // these are applied to the drawable - private ColorFilter mColorFilter; - private Xfermode mXfermode; - private int mAlpha = 255; - private int mViewAlphaScale = 256; - private boolean mColorMod = false; - - private Drawable mDrawable = null; - private int[] mState = null; - private boolean mMergeState = false; - private int mLevel = 0; - private int mDrawableWidth; - private int mDrawableHeight; - private Matrix mDrawMatrix = null; - - // Avoid allocations... - private RectF mTempSrc = new RectF(); - private RectF mTempDst = new RectF(); - - private boolean mCropToPadding; - - private int mBaseline = -1; - private boolean mBaselineAlignBottom = false; - - // AdjustViewBounds behavior will be in compatibility mode for older apps. - private boolean mAdjustViewBoundsCompat = false; - - private static final ScaleType[] sScaleTypeArray = { ScaleType.MATRIX, - ScaleType.FIT_XY, ScaleType.FIT_START, ScaleType.FIT_CENTER, - ScaleType.FIT_END, ScaleType.CENTER, ScaleType.CENTER_CROP, - ScaleType.CENTER_INSIDE }; - - public SuperImageView(Context context) { - super(context); - initImageView(); - } - - public SuperImageView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public SuperImageView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initImageView(); - - TypedArray a = context.obtainStyledAttributes(attrs, - R.styleable.SuperImageView, defStyle, 0); - - mBaselineAlignBottom = a.getBoolean( - R.styleable.SuperImageView_baselineAlignBottom, false); - - mBaseline = a.getDimensionPixelSize( - R.styleable.SuperImageView_baseline, -1); - - setAdjustViewBounds(a.getBoolean( - R.styleable.SuperImageView_adjustViewBounds, false)); - - setMaxWidth(a.getDimensionPixelSize( - R.styleable.SuperImageView_maxWidth, Integer.MAX_VALUE)); - - setMaxHeight(a.getDimensionPixelSize( - R.styleable.SuperImageView_maxHeight, Integer.MAX_VALUE)); - - int index = a.getInt(R.styleable.SuperImageView_scaleType, -1); - if (index >= 0) { - setScaleType(sScaleTypeArray[index]); - } - - int tint = a.getInt(R.styleable.SuperImageView_tint, 0); - if (tint != 0) { - setColorFilter(tint); - } - - int alpha = a.getInt(R.styleable.SuperImageView_drawableAlpha, 255); - if (alpha != 255) { - setAlpha(alpha); - } - - mCropToPadding = a.getBoolean(R.styleable.SuperImageView_cropToPadding, - false); - - int resId = a.getResourceId(R.styleable.SuperImageView_src, -1); - if (resId == -1) { - Drawable d = a.getDrawable(R.styleable.SuperImageView_src); - if (d != null) { - setImageDrawable(d); - } - } else - this.setImageResource(resId); - - a.recycle(); - - // need inflate syntax/reader for matrix - } - - private void initImageView() { - mMatrix = new Matrix(); - mScaleType = ScaleType.FIT_CENTER; - mAdjustViewBoundsCompat = getContext().getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; - } - - @Override - protected boolean verifyDrawable(Drawable dr) { - return mDrawable == dr || super.verifyDrawable(dr); - } - - protected boolean verifyMovie(Movie mv) { - return mMovie == mv; - } - - @SuppressLint("NewApi") - @Override - public void jumpDrawablesToCurrentState() { - if (Build.VERSION.SDK_INT < 11) { - return; - } - - super.jumpDrawablesToCurrentState(); - if (mDrawable != null) - mDrawable.jumpToCurrentState(); - } - - @Override - public void invalidateDrawable(Drawable dr) { - if (dr == mDrawable) { - /* - * we invalidate the whole view in this case because it's very hard - * to know where the drawable actually is. This is made complicated - * because of the offsets and transformations that can be applied. - * In theory we could get the drawable's bounds and run them through - * the transformation and offsets, but this is probably not worth - * the effort. - */ - invalidate(); - } else { - super.invalidateDrawable(dr); - } - } - - public void invalidateMovie(Movie mv) { - if (mv == mMovie) { - /* - * we invalidate the whole view in this case because it's very hard - * to know where the drawable actually is. This is made complicated - * because of the offsets and transformations that can be applied. - * In theory we could get the drawable's bounds and run them through - * the transformation and offsets, but this is probably not worth - * the effort. - */ - invalidate(); - } - } - - @Override - public boolean hasOverlappingRendering() { - return (getBackground() != null && getBackground().getCurrent() != null); - } - - @SuppressLint("NewApi") - @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - if (Build.VERSION.SDK_INT < 14) { - return; - } - - super.onPopulateAccessibilityEvent(event); - CharSequence contentDescription = getContentDescription(); - if (!TextUtils.isEmpty(contentDescription)) { - event.getText().add(contentDescription); - } - } - - /** - * True when ImageView is adjusting its bounds to preserve the aspect ratio - * of its drawable - * - * @return whether to adjust the bounds of this view to presrve the original - * aspect ratio of the drawable - * - * @see #setAdjustViewBounds(boolean) - * - * @attr ref android.R.styleable#ImageView_adjustViewBounds - */ - public boolean getAdjustViewBounds() { - return mAdjustViewBounds; - } - - /** - * Set this to true if you want the ImageView to adjust its bounds to - * preserve the aspect ratio of its drawable. - * - *
- * Note: If the application targets API level 17 or lower, - * adjustViewBounds will allow the drawable to shrink the view bounds, but - * not grow to fill available measured space in all cases. This is for - * compatibility with legacy {@link android.view.View.MeasureSpec - * MeasureSpec} and {@link android.widget.RelativeLayout RelativeLayout} - * behavior. - *
- * - * @param adjustViewBounds - * Whether to adjust the bounds of this view to preserve the - * original aspect ratio of the drawable. - * - * @see #getAdjustViewBounds() - * - * @attr ref android.R.styleable#ImageView_adjustViewBounds - */ - public void setAdjustViewBounds(boolean adjustViewBounds) { - mAdjustViewBounds = adjustViewBounds; - if (adjustViewBounds) { - setScaleType(ScaleType.FIT_CENTER); - } - } - - /** - * The maximum width of this view. - * - * @return The maximum width of this view - * - * @see #setMaxWidth(int) - * - * @attr ref android.R.styleable#ImageView_maxWidth - */ - public int getMaxWidth() { - return mMaxWidth; - } - - /** - * An optional argument to supply a maximum width for this view. Only valid - * if {@link #setAdjustViewBounds(boolean)} has been set to true. To set an - * image to be a maximum of 100 x 100 while preserving the original aspect - * ratio, do the following: 1) set adjustViewBounds to true 2) set maxWidth - * and maxHeight to 100 3) set the height and width layout params to - * WRAP_CONTENT. - * - *- * Note that this view could be still smaller than 100 x 100 using this - * approach if the original image is small. To set an image to a fixed size, - * specify that size in the layout params and then use - * {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine - * how to fit the image within the bounds. - *
- * - * @param maxWidth - * maximum width for this view - * - * @see #getMaxWidth() - * - * @attr ref android.R.styleable#ImageView_maxWidth - */ - public void setMaxWidth(int maxWidth) { - mMaxWidth = maxWidth; - } - - /** - * The maximum height of this view. - * - * @return The maximum height of this view - * - * @see #setMaxHeight(int) - * - * @attr ref android.R.styleable#ImageView_maxHeight - */ - public int getMaxHeight() { - return mMaxHeight; - } - - /** - * An optional argument to supply a maximum height for this view. Only valid - * if {@link #setAdjustViewBounds(boolean)} has been set to true. To set an - * image to be a maximum of 100 x 100 while preserving the original aspect - * ratio, do the following: 1) set adjustViewBounds to true 2) set maxWidth - * and maxHeight to 100 3) set the height and width layout params to - * WRAP_CONTENT. - * - *- * Note that this view could be still smaller than 100 x 100 using this - * approach if the original image is small. To set an image to a fixed size, - * specify that size in the layout params and then use - * {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine - * how to fit the image within the bounds. - *
- * - * @param maxHeight - * maximum height for this view - * - * @see #getMaxHeight() - * - * @attr ref android.R.styleable#ImageView_maxHeight - */ - public void setMaxHeight(int maxHeight) { - mMaxHeight = maxHeight; - } - - /** - * Return the view's drawable, or null if no drawable has been assigned. - */ - public Drawable getDrawable() { - return mDrawable; - } - - public int getResourceWidth() { - return mDrawableWidth; - } - - public int getResourceHeight() { - return mDrawableHeight; - } - - public Movie getMovie() { - return mMovie; - } - - public boolean isEmpty() { - if (mMovie == null && mDrawable == null) - return true; - else - return false; - } - - /** - * Sets a drawable as the content of this ImageView. - * - *- * This does Bitmap reading and decoding on the UI thread, which can cause a - * latency hiccup. If that's a concern, consider using - * {@link #setImageDrawable(android.graphics.drawable.Drawable)} or - * {@link #setImageBitmap(android.graphics.Bitmap)} and - * {@link android.graphics.BitmapFactory} instead. - *
- * - * @param resId - * the resource identifier of the drawable - * - * @attr ref android.R.styleable#ImageView_src - */ - public void setImageResource(int resId) { - if (mUri != null || mResource != resId) { - updateDrawable(null); - updateMovie(null); - mResource = resId; - mUri = null; - - final int oldWidth = mDrawableWidth; - final int oldHeight = mDrawableHeight; - - resolveUri(); - - if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { - requestLayout(); - } - invalidate(); - } - } - - /** - * Sets the content of this ImageView to the specified Uri. - * - *- * This does Bitmap reading and decoding on the UI thread, which can cause a - * latency hiccup. If that's a concern, consider using - * {@link #setImageDrawable(android.graphics.drawable.Drawable)} or - * {@link #setImageBitmap(android.graphics.Bitmap)} and - * {@link android.graphics.BitmapFactory} instead. - *
- * - * @param uri - * The Uri of an image - */ - public void setImageURI(Uri uri) { - if (mResource != 0 - || (mUri != uri && (uri == null || mUri == null || !uri - .equals(mUri)))) { - updateDrawable(null); - updateMovie(null); - mResource = 0; - mUri = uri; - - final int oldWidth = mDrawableWidth; - final int oldHeight = mDrawableHeight; - - resolveUri(); - - if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { - requestLayout(); - } - invalidate(); - } - } - - /** - * Sets a drawable as the content of this ImageView. - * - * @param drawable - * The drawable to set - */ - public void setImageDrawable(Drawable drawable) { - if (mDrawable != drawable) { - mResource = 0; - mUri = null; - mMovie = null; - - final int oldWidth = mDrawableWidth; - final int oldHeight = mDrawableHeight; - - updateDrawable(drawable); - updateMovie(null); - - if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { - requestLayout(); - } - invalidate(); - } - } - - /** - * Sets a Movie as the content of this SuperImageView. - * - * @param mv - * The movie to set - */ - public void setImageMovie(Movie mv) { - if (mMovie != mv) { - mResource = 0; - mUri = null; - mDrawable = null; - - final int oldWidth = mDrawableWidth; - final int oldHeight = mDrawableHeight; - - updateDrawable(null); - updateMovie(mv); - - if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { - requestLayout(); - } - invalidate(); - } - } - - /** - * Sets a InputStream as the content of this SuperImageView. - * - * @param is - * The InputStream to set - */ - public void setImageInputStream(InputStream is) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int len; - while ((len = is.read(buffer)) > -1) { - baos.write(buffer, 0, len); - } - is.close(); - baos.flush(); - - byte[] bytes = baos.toByteArray(); - Movie m = Movie.decodeByteArray(bytes, 0, bytes.length); - if (m == null) { - Bitmap b = BitmapFactory - .decodeByteArray(bytes, 0, bytes.length); - setImageBitmap(b); - } else - setImageMovie(m); - - baos.close(); - } catch (IOException e) { - Log.e(TAG, "Set Image from InputStream error !"); - } - } - - /** - * Sets a Bitmap as the content of this ImageView. - * - * @param bm - * The bitmap to set - */ - public void setImageBitmap(Bitmap bm) { - // if this is used frequently, may handle bitmaps explicitly - // to reduce the intermediate drawable object - setImageDrawable(new BitmapDrawable(getContext().getResources(), bm)); - } - - public void setImageState(int[] state, boolean merge) { - mState = state; - mMergeState = merge; - if (mDrawable != null) { - refreshDrawableState(); - resizeFromResource(); - } - } - - @Override - public void setSelected(boolean selected) { - super.setSelected(selected); - resizeFromResource(); - } - - /** - * Sets the image level, when it is constructed from a - * {@link android.graphics.drawable.LevelListDrawable}. - * - * @param level - * The new level for the image. - */ - public void setImageLevel(int level) { - mLevel = level; - if (mDrawable != null) { - mDrawable.setLevel(level); - resizeFromResource(); - } - } - - /** - * Options for scaling the bounds of an image to the bounds of this view. - */ - public enum ScaleType { - /** - * Scale using the image matrix when drawing. The image matrix can be - * set using {@link SuperImageView#setImageMatrix(Matrix)}. From XML, - * use this syntax:android:scaleType="matrix".
- */
- MATRIX(0),
- /**
- * Scale the image using {@link Matrix.ScaleToFit#FILL}. From XML, use
- * this syntax: android:scaleType="fitXY".
- */
- FIT_XY(1),
- /**
- * Scale the image using {@link Matrix.ScaleToFit#START}. From XML, use
- * this syntax: android:scaleType="fitStart".
- */
- FIT_START(2),
- /**
- * Scale the image using {@link Matrix.ScaleToFit#CENTER}. From XML, use
- * this syntax: android:scaleType="fitCenter".
- */
- FIT_CENTER(3),
- /**
- * Scale the image using {@link Matrix.ScaleToFit#END}. From XML, use
- * this syntax: android:scaleType="fitEnd".
- */
- FIT_END(4),
- /**
- * Center the image in the view, but perform no scaling. From XML, use
- * this syntax: android:scaleType="center".
- */
- CENTER(5),
- /**
- * Scale the image uniformly (maintain the image's aspect ratio) so that
- * both dimensions (width and height) of the image will be equal to or
- * larger than the corresponding dimension of the view (minus padding).
- * The image is then centered in the view. From XML, use this syntax:
- * android:scaleType="centerCrop".
- */
- CENTER_CROP(6),
- /**
- * Scale the image uniformly (maintain the image's aspect ratio) so that
- * both dimensions (width and height) of the image will be equal to or
- * less than the corresponding dimension of the view (minus padding).
- * The image is then centered in the view. From XML, use this syntax:
- * android:scaleType="centerInside".
- */
- CENTER_INSIDE(7);
-
- ScaleType(int ni) {
- nativeInt = ni;
- }
-
- final int nativeInt;
- }
-
- /**
- * Controls how the image should be resized or moved to match the size of
- * this ImageView.
- *
- * @param scaleType
- * The desired scaling mode.
- *
- * @attr ref android.R.styleable#ImageView_scaleType
- */
- public void setScaleType(ScaleType scaleType) {
- if (scaleType == null) {
- throw new NullPointerException();
- }
-
- if (mScaleType != scaleType) {
- mScaleType = scaleType;
-
- setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);
-
- requestLayout();
- invalidate();
- }
- }
-
- /**
- * Return the current scale type in use by this ImageView.
- *
- * @see SuperImageView.ScaleType
- *
- * @attr ref android.R.styleable#ImageView_scaleType
- */
- public ScaleType getScaleType() {
- return mScaleType;
- }
-
- /**
- * Return the view's optional matrix. This is applied to the view's drawable
- * when it is drawn. If there is not matrix, this method will return an
- * identity matrix. Do not change this matrix in place but make a copy. If
- * you want a different matrix applied to the drawable, be sure to call
- * setImageMatrix().
- */
- public Matrix getImageMatrix() {
- if (mDrawMatrix == null) {
- // return new Matrix(Matrix.IDENTITY_MATRIX); //TODO Fix here
- return new Matrix();
- }
- return mDrawMatrix;
- }
-
- public void setImageMatrix(Matrix matrix) {
- // collaps null and identity to just null
- if (matrix != null && matrix.isIdentity()) {
- matrix = null;
- }
-
- // don't invalidate unless we're actually changing our matrix
- if (matrix == null && !mMatrix.isIdentity() || matrix != null
- && !mMatrix.equals(matrix)) {
- mMatrix.set(matrix);
- configureBounds();
- invalidate();
- }
- }
-
- /**
- * Return whether this ImageView crops to padding.
- *
- * @return whether this ImageView crops to padding
- *
- * @see #setCropToPadding(boolean)
- *
- * @attr ref android.R.styleable#ImageView_cropToPadding
- */
- public boolean getCropToPadding() {
- return mCropToPadding;
- }
-
- /**
- * Sets whether this ImageView will crop to padding.
- *
- * @param cropToPadding
- * whether this ImageView will crop to padding
- *
- * @see #getCropToPadding()
- *
- * @attr ref android.R.styleable#ImageView_cropToPadding
- */
- public void setCropToPadding(boolean cropToPadding) {
- if (mCropToPadding != cropToPadding) {
- mCropToPadding = cropToPadding;
- requestLayout();
- invalidate();
- }
- }
-
- private void resolveUri() {
- if (mDrawable != null && mMovie != null) {
- return;
- }
-
- Resources rsrc = getResources();
- if (rsrc == null) {
- return;
- }
-
- Drawable d = null;
- Movie m = null;
-
- if (mResource != 0) {
- try {
- InputStream is = rsrc.openRawResource(mResource);
- m = Movie.decodeStream(is);
- if (m == null) {
- d = rsrc.getDrawable(mResource);
- }
- } catch (Exception e) {
- Log.w("ImageView", "Unable to find resource: " + mResource, e);
- // Don't try again.
- mUri = null;
- }
- } else if (mUri != null) {
- String scheme = mUri.getScheme();
- /*
- * if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) { //
- * TODO Can't fix here try { // Load drawable through Resources, to
- * get the source density information
- * ContentResolver.OpenResourceIdResult r =
- * getContext().getContentResolver().getResourceId(mUri); d =
- * r.r.getDrawable(r.id); } catch (Exception e) { Log.w("ImageView",
- * "Unable to open content: " + mUri, e); } } else
- */if (ContentResolver.SCHEME_CONTENT.equals(scheme)
- || ContentResolver.SCHEME_FILE.equals(scheme)) {
- InputStream stream = null;
- try {
- stream = getContext().getContentResolver().openInputStream(
- mUri);
- m = Movie.decodeStream(stream);
- if (m == null) {
- stream = getContext().getContentResolver()
- .openInputStream(mUri);
- d = Drawable.createFromStream(stream, null);
- }
- } catch (Exception e) {
- Log.w("ImageView", "Unable to open content: " + mUri, e);
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- Log.w("ImageView", "Unable to close content: "
- + mUri, e);
- }
- }
- }
- } else {
- d = Drawable.createFromPath(mUri.toString());
- }
- if (d == null && m == null) {
- System.out.println("resolveUri failed on bad bitmap uri: "
- + mUri);
- // Don't try again.
- mUri = null;
- }
- } else {
- return;
- }
-
- updateDrawable(d);
- updateMovie(m);
- }
-
- @Override
- public int[] onCreateDrawableState(int extraSpace) {
- if (mState == null) {
- return super.onCreateDrawableState(extraSpace);
- } else if (!mMergeState) {
- return mState;
- } else {
- return mergeDrawableStates(
- super.onCreateDrawableState(extraSpace + mState.length),
- mState);
- }
- }
-
- private void updateDrawable(Drawable d) {
- if (mDrawable != null) {
- mDrawable.setCallback(null);
- unscheduleDrawable(mDrawable);
- }
- mDrawable = d;
- if (d != null) {
- d.setCallback(this);
- if (d.isStateful()) {
- d.setState(getDrawableState());
- }
- d.setLevel(mLevel);
- // d.setLayoutDirection(getLayoutDirection()); // TODO Can't fix, reflection?
- // here
- d.setVisible(getVisibility() == VISIBLE, true);
- mDrawableWidth = d.getIntrinsicWidth();
- mDrawableHeight = d.getIntrinsicHeight();
- applyColorMod();
- configureBounds();
- } else {
- mDrawableWidth = mDrawableHeight = -1;
- }
- }
-
- private void updateMovie(Movie m) {
- mMovie = m;
- if (m != null) {
- mMovieStart = 0;
- mCurrentAnimationTime = 0;
- mDrawableWidth = m.width();
- mDrawableHeight = m.height();
- applyColorMod();
- configureBounds();
- }
- }
-
- private void resizeFromResource() {
- Drawable d = mDrawable;
- Movie m = mMovie;
- if (d != null) {
- int w = d.getIntrinsicWidth();
- if (w < 0)
- w = mDrawableWidth;
- int h = d.getIntrinsicHeight();
- if (h < 0)
- h = mDrawableHeight;
- if (w != mDrawableWidth || h != mDrawableHeight) {
- mDrawableWidth = w;
- mDrawableHeight = h;
- requestLayout();
- }
- } else if (m != null) {
- int w = m.width();
- if (w < 0)
- w = mDrawableWidth;
- int h = m.height();
- if (h < 0)
- h = mDrawableHeight;
- if (w != mDrawableWidth || h != mDrawableHeight) {
- mDrawableWidth = w;
- mDrawableHeight = h;
- requestLayout();
- }
- }
- }
-
- @SuppressLint("NewApi")
- @Override
- public void onRtlPropertiesChanged(int layoutDirection) {
- if (Build.VERSION.SDK_INT < 17) {
- return;
- }
-
- super.onRtlPropertiesChanged(layoutDirection);
-
- if (mDrawable != null) {
- // mDrawable.setLayoutDirection(layoutDirection); // TODO Can't fix, reflection?
- // here
- }
- }
-
- private static final Matrix.ScaleToFit[] sS2FArray = {
- Matrix.ScaleToFit.FILL, Matrix.ScaleToFit.START,
- Matrix.ScaleToFit.CENTER, Matrix.ScaleToFit.END };
-
- private static Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType st) {
- // ScaleToFit enum to their corresponding Matrix.ScaleToFit values
- return sS2FArray[st.nativeInt - 1];
- }
-
- @SuppressLint("NewApi")
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- resolveUri();
- int w;
- int h;
-
- // Desired aspect ratio of the view's contents (not including padding)
- float desiredAspect = 0.0f;
-
- // We are allowed to change the view's width
- boolean resizeWidth = false;
-
- // We are allowed to change the view's height
- boolean resizeHeight = false;
-
- final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
-
- if (mDrawable == null && mMovie == null) {
- // If no drawable, its intrinsic size is 0.
- mDrawableWidth = -1;
- mDrawableHeight = -1;
- w = h = 0;
- } else {
- w = mDrawableWidth;
- h = mDrawableHeight;
- if (w <= 0)
- w = 1;
- if (h <= 0)
- h = 1;
-
- // We are supposed to adjust view bounds to match the aspect
- // ratio of our drawable. See if that is possible.
- if (mAdjustViewBounds) {
- resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
- resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
-
- desiredAspect = (float) w / (float) h;
- }
- }
-
- int pleft = getPaddingLeft();
- int pright = getPaddingRight();
- int ptop = getPaddingTop();
- int pbottom = getPaddingBottom();
-
- int widthSize;
- int heightSize;
-
- if (resizeWidth || resizeHeight) {
- /*
- * If we get here, it means we want to resize to match the drawables
- * aspect ratio, and we have the freedom to change at least one
- * dimension.
- */
-
- // Get the max possible width given our constraints
- widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth,
- widthMeasureSpec);
-
- // Get the max possible height given our constraints
- heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight,
- heightMeasureSpec);
-
- if (desiredAspect != 0.0f) {
- // See what our actual aspect ratio is
- float actualAspect = (float) (widthSize - pleft - pright)
- / (heightSize - ptop - pbottom);
-
- if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
-
- boolean done = false;
-
- // Try adjusting width to be proportional to height
- if (resizeWidth) {
- int newWidth = (int) (desiredAspect * (heightSize
- - ptop - pbottom))
- + pleft + pright;
-
- // Allow the width to outgrow its original estimate if
- // height is fixed.
- if (!resizeHeight && !mAdjustViewBoundsCompat) {
- widthSize = resolveAdjustedSize(newWidth,
- mMaxWidth, widthMeasureSpec);
- }
-
- if (newWidth <= widthSize) {
- widthSize = newWidth;
- done = true;
- }
- }
-
- // Try adjusting height to be proportional to width
- if (!done && resizeHeight) {
- int newHeight = (int) ((widthSize - pleft - pright) / desiredAspect)
- + ptop + pbottom;
-
- // Allow the height to outgrow its original estimate if
- // width is fixed.
- if (!resizeWidth && !mAdjustViewBoundsCompat) {
- heightSize = resolveAdjustedSize(newHeight,
- mMaxHeight, heightMeasureSpec);
- }
-
- if (newHeight <= heightSize) {
- heightSize = newHeight;
- }
- }
- }
- }
- } else {
- /*
- * We are either don't want to preserve the drawables aspect ratio,
- * or we are not allowed to change view dimensions. Just measure in
- * the normal way.
- */
- w += pleft + pright;
- h += ptop + pbottom;
-
- w = Math.max(w, getSuggestedMinimumWidth());
- h = Math.max(h, getSuggestedMinimumHeight());
-
- if (Build.VERSION.SDK_INT < 11) {
- widthSize = resolveSize(w, widthMeasureSpec);
- heightSize = resolveSize(h, heightMeasureSpec);
- } else {
- widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
- heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
- }
- }
-
- setMeasuredDimension(widthSize, heightSize);
- }
-
- private int resolveAdjustedSize(int desiredSize, int maxSize,
- int measureSpec) {
- int result = desiredSize;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- switch (specMode) {
- case MeasureSpec.UNSPECIFIED:
- /*
- * Parent says we can be as big as we want. Just don't be larger
- * than max size imposed on ourselves.
- */
- result = Math.min(desiredSize, maxSize);
- break;
- case MeasureSpec.AT_MOST:
- // Parent says we can be as big as we want, up to specSize.
- // Don't be larger than specSize, and don't be larger than
- // the max size imposed on ourselves.
- result = Math.min(Math.min(desiredSize, specSize), maxSize);
- break;
- case MeasureSpec.EXACTLY:
- // No choice. Do what we are told.
- result = specSize;
- break;
- }
- return result;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right,
- int bottom) {
- configureBounds();
- }
-
- private void configureBounds() {
- if (mDrawable == null && mMovie == null) {
- return;
- }
-
- int dwidth = mDrawableWidth;
- int dheight = mDrawableHeight;
-
- int vwidth = getWidth() - getPaddingLeft() - getPaddingRight();
- int vheight = getHeight() - getPaddingTop() - getPaddingBottom();
-
- boolean fits = (dwidth < 0 || vwidth == dwidth)
- && (dheight < 0 || vheight == dheight);
-
- if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
- /*
- * If the drawable has no intrinsic size, or we're told to
- * scaletofit, then we just fill our entire view.
- */
- if (mDrawable != null) {
- mDrawable.setBounds(0, 0, vwidth, vheight);
- mDrawMatrix = null;
- } else if (dheight > 0 && dheight > 0) {
- mDrawMatrix = new Matrix();
- mDrawMatrix.setScale((float) vwidth / dwidth, (float) vheight
- / dheight);
- }
-
- } else {
- // We need to do the scaling ourself, so have the drawable
- // use its native size.
- if (mDrawable != null)
- mDrawable.setBounds(0, 0, dwidth, dheight);
-
- if (ScaleType.MATRIX == mScaleType) {
- // Use the specified matrix as-is.
- if (mMatrix.isIdentity()) {
- mDrawMatrix = null;
- } else {
- mDrawMatrix = mMatrix;
- }
- } else if (fits) {
- // The bitmap fits exactly, no transform needed.
- mDrawMatrix = null;
- } else if (ScaleType.CENTER == mScaleType) {
- // Center bitmap in view, no scaling.
- mDrawMatrix = mMatrix;
- mDrawMatrix.setTranslate(
- (int) ((vwidth - dwidth) * 0.5f + 0.5f),
- (int) ((vheight - dheight) * 0.5f + 0.5f));
- } else if (ScaleType.CENTER_CROP == mScaleType) {
- mDrawMatrix = mMatrix;
-
- float scale;
- float dx = 0, dy = 0;
-
- if (dwidth * vheight > vwidth * dheight) {
- scale = (float) vheight / (float) dheight;
- dx = (vwidth - dwidth * scale) * 0.5f;
- } else {
- scale = (float) vwidth / (float) dwidth;
- dy = (vheight - dheight * scale) * 0.5f;
- }
-
- mDrawMatrix.setScale(scale, scale);
- mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
- } else if (ScaleType.CENTER_INSIDE == mScaleType) {
- mDrawMatrix = mMatrix;
- float scale;
- float dx;
- float dy;
-
- if (dwidth <= vwidth && dheight <= vheight) {
- scale = 1.0f;
- } else {
- scale = Math.min((float) vwidth / (float) dwidth,
- (float) vheight / (float) dheight);
- }
-
- dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
- dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);
-
- mDrawMatrix.setScale(scale, scale);
- mDrawMatrix.postTranslate(dx, dy);
- } else {
- // Generate the required transform.
- mTempSrc.set(0, 0, dwidth, dheight);
- mTempDst.set(0, 0, vwidth, vheight);
-
- mDrawMatrix = mMatrix;
- mDrawMatrix.setRectToRect(mTempSrc, mTempDst,
- scaleTypeToScaleToFit(mScaleType));
- }
- }
- }
-
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
- Drawable d = mDrawable;
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (mDrawable == null && mMovie == null) {
- return; // couldn't resolve the URI
- }
-
- if (mDrawableWidth == 0 || mDrawableHeight == 0) {
- return; // nothing to draw (empty bounds)
- }
-
- int pLeft = getPaddingLeft();
-
- if (mDrawMatrix == null && getPaddingTop() == 0 && pLeft == 0) {
- if (mDrawable != null)
- mDrawable.draw(canvas);
- else
- drawMovieFrame(canvas);
- } else {
- int saveCount = canvas.getSaveCount();
- canvas.save();
-
- if (mCropToPadding) {
- final int scrollX = getScrollX();
- final int scrollY = getScrollY();
- canvas.clipRect(scrollX + pLeft, scrollY + getPaddingTop(),
- scrollX + getRight() - getLeft() - getPaddingRight(), scrollY
- + getBottom() - getTop() - getPaddingBottom());
- }
-
- canvas.translate(pLeft, getPaddingTop());
-
- if (mDrawMatrix != null) {
- canvas.concat(mDrawMatrix);
- }
- if (mDrawable != null)
- mDrawable.draw(canvas);
- else
- drawMovieFrame(canvas);
- canvas.restoreToCount(saveCount);
- }
- }
-
- @SuppressLint("NewApi")
- private void drawMovieFrame(Canvas canvas) {
- // if (!mPaused)
- updateAnimationTime();
-
- mMovie.setTime(mCurrentAnimationTime);
- mMovie.draw(canvas, 0, 0);
-
- // if (!mPaused)
- if (Build.VERSION.SDK_INT < 16) {
- invalidate();
- } else {
- postInvalidateOnAnimation();
- }
- }
-
- private void updateAnimationTime() {
- long now = android.os.SystemClock.uptimeMillis();
-
- if (mMovieStart == 0) {
- mMovieStart = now;
- }
-
- int dur = mMovie.duration();
-
- if (dur == 0) {
- dur = DEFAULT_MOVIEW_DURATION;
- }
-
- mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
- }
-
- /**
- * - * Return the offset of the widget's text baseline from the widget's top - * boundary. - *
- * - * @return the offset of the baseline within the widget's bounds or -1 if - * baseline alignment is not supported. - */ - @Override - @ViewDebug.ExportedProperty(category = "layout") - public int getBaseline() { - if (mBaselineAlignBottom) { - return getMeasuredHeight(); - } else { - return mBaseline; - } - } - - /** - *- * Set the offset of the widget's text baseline from the widget's top - * boundary. This value is overridden by the - * {@link #setBaselineAlignBottom(boolean)} property. - *
- * - * @param baseline - * The baseline to use, or -1 if none is to be provided. - * - * @see #setBaseline(int) - * @attr ref android.R.styleable#ImageView_baseline - */ - public void setBaseline(int baseline) { - if (mBaseline != baseline) { - mBaseline = baseline; - requestLayout(); - } - } - - /** - * Set whether to set the baseline of this view to the bottom of the view. - * Setting this value overrides any calls to setBaseline. - * - * @param aligned - * If true, the image view will be baseline aligned with based on - * its bottom edge. - * - * @attr ref android.R.styleable#ImageView_baselineAlignBottom - */ - public void setBaselineAlignBottom(boolean aligned) { - if (mBaselineAlignBottom != aligned) { - mBaselineAlignBottom = aligned; - requestLayout(); - } - } - - /** - * Return whether this view's baseline will be considered the bottom of the - * view. - * - * @see #setBaselineAlignBottom(boolean) - */ - public boolean getBaselineAlignBottom() { - return mBaselineAlignBottom; - } - - /** - * Set a tinting option for the image. - * - * @param color - * Color tint to apply. - * @param mode - * How to apply the color. The standard mode is - * {@link PorterDuff.Mode#SRC_ATOP} - * - * @attr ref android.R.styleable#ImageView_tint - */ - public final void setColorFilter(int color, PorterDuff.Mode mode) { - setColorFilter(new PorterDuffColorFilter(color, mode)); - } - - /** - * Set a tinting option for the image. Assumes - * {@link PorterDuff.Mode#SRC_ATOP} blending mode. - * - * @param color - * Color tint to apply. - * @attr ref android.R.styleable#ImageView_tint - */ - public final void setColorFilter(int color) { - setColorFilter(color, PorterDuff.Mode.SRC_ATOP); - } - - public final void clearColorFilter() { - setColorFilter(null); - } - - /** - * @hide Candidate for future API inclusion - */ - public final void setXfermode(Xfermode mode) { - if (mXfermode != mode) { - mXfermode = mode; - mColorMod = true; - applyColorMod(); - invalidate(); - } - } - - /** - * Returns the active color filter for this ImageView. - * - * @return the active color filter for this ImageView - * - * @see #setColorFilter(android.graphics.ColorFilter) - */ - public ColorFilter getColorFilter() { - return mColorFilter; - } - - /** - * Apply an arbitrary colorfilter to the image. - * - * @param cf - * the colorfilter to apply (may be null) - * - * @see #getColorFilter() - */ - public void setColorFilter(ColorFilter cf) { - if (mColorFilter != cf) { - mColorFilter = cf; - mColorMod = true; - applyColorMod(); - invalidate(); - } - } - - /** - * Returns the alpha that will be applied to the drawable of this ImageView. - * - * @return the alpha that will be applied to the drawable of this ImageView - * - * @see #setImageAlpha(int) - */ - public int getImageAlpha() { - return mAlpha; - } - - /** - * Sets the alpha value that should be applied to the image. - * - * @param alpha - * the alpha value that should be applied to the image - * - * @see #getImageAlpha() - */ - public void setImageAlpha(int alpha) { - setAlpha(alpha); - } - - /** - * Sets the alpha value that should be applied to the image. - * - * @param alpha - * the alpha value that should be applied to the image - * - * @deprecated use #setImageAlpha(int) instead - */ - @Deprecated - public void setAlpha(int alpha) { - alpha &= 0xFF; // keep it legal - if (mAlpha != alpha) { - mAlpha = alpha; - mColorMod = true; - applyColorMod(); - invalidate(); - } - } - - private void applyColorMod() { - // Only mutate and apply when modifications have occurred. This should - // not reset the mColorMod flag, since these filters need to be - // re-applied if the Drawable is changed. - if (mDrawable != null && mColorMod) { - mDrawable = mDrawable.mutate(); - mDrawable.setColorFilter(mColorFilter); - // mDrawable.setXfermode(mXfermode); // Can't fix here - mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8); - } - } - - @Override - public void setVisibility(int visibility) { - super.setVisibility(visibility); - if (mDrawable != null) { - mDrawable.setVisible(visibility == VISIBLE, false); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (mDrawable != null) { - mDrawable.setVisible(getVisibility() == VISIBLE, false); - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (mDrawable != null) { - mDrawable.setVisible(false, false); - } - } - - @SuppressLint("NewApi") - @Override - public void onInitializeAccessibilityEvent(AccessibilityEvent event) { - if (Build.VERSION.SDK_INT < 14) { - return; - } - - super.onInitializeAccessibilityEvent(event); - event.setClassName(SuperImageView.class.getName()); - } - - @SuppressLint("NewApi") - @Override - public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { - if (Build.VERSION.SDK_INT < 14) { - return; - } - super.onInitializeAccessibilityNodeInfo(info); - info.setClassName(SuperImageView.class.getName()); - } +package com.hippo.ehviewer.view; + +import android.annotation.SuppressLint; +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Matrix; +import android.graphics.Movie; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.RectF; +import android.graphics.Xfermode; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; +import android.util.AttributeSet; +import com.hippo.ehviewer.util.Log; +import android.view.View; +import android.view.ViewDebug; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.RemoteViews.RemoteView; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; + +import com.hippo.ehviewer.R; + +// TODO use native to improve gif + +/** + * Displays an arbitrary image, such as an icon. The ImageView class can load + * images from various sources (such as resources or content providers), takes + * care of computing its measurement from the image so that it can be used in + * any layout manager, and provides various display options such as scaling and + * tinting. + * + * @attr ref android.R.styleable#ImageView_adjustViewBounds + * @attr ref android.R.styleable#ImageView_src + * @attr ref android.R.styleable#ImageView_maxWidth + * @attr ref android.R.styleable#ImageView_maxHeight + * @attr ref android.R.styleable#ImageView_tint + * @attr ref android.R.styleable#ImageView_scaleType + * @attr ref android.R.styleable#ImageView_cropToPadding + */ +@RemoteView +public class SuperImageView extends View { + private static String TAG = "SuperImageView"; + // for gif + private Movie mMovie = null; + // Not 0 mean the same timer + private long mMovieStart = 1; + private int mCurrentAnimationTime = 0; + + private static final int DEFAULT_MOVIEW_DURATION = 1000; + + // settable by the client + private Uri mUri; + private int mResource = 0; + private Matrix mMatrix; + private ScaleType mScaleType; + private boolean mHaveFrame = false; + private boolean mAdjustViewBounds = false; + private int mMaxWidth = Integer.MAX_VALUE; + private int mMaxHeight = Integer.MAX_VALUE; + + // these are applied to the drawable + private ColorFilter mColorFilter; + private Xfermode mXfermode; + private int mAlpha = 255; + private int mViewAlphaScale = 256; + private boolean mColorMod = false; + + private Drawable mDrawable = null; + private int[] mState = null; + private boolean mMergeState = false; + private int mLevel = 0; + private int mDrawableWidth; + private int mDrawableHeight; + private Matrix mDrawMatrix = null; + + // Avoid allocations... + private RectF mTempSrc = new RectF(); + private RectF mTempDst = new RectF(); + + private boolean mCropToPadding; + + private int mBaseline = -1; + private boolean mBaselineAlignBottom = false; + + // AdjustViewBounds behavior will be in compatibility mode for older apps. + private boolean mAdjustViewBoundsCompat = false; + + private static final ScaleType[] sScaleTypeArray = { ScaleType.MATRIX, + ScaleType.FIT_XY, ScaleType.FIT_START, ScaleType.FIT_CENTER, + ScaleType.FIT_END, ScaleType.CENTER, ScaleType.CENTER_CROP, + ScaleType.CENTER_INSIDE }; + + public SuperImageView(Context context) { + super(context); + initImageView(); + } + + public SuperImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SuperImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initImageView(); + + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.SuperImageView, defStyle, 0); + + mBaselineAlignBottom = a.getBoolean( + R.styleable.SuperImageView_baselineAlignBottom, false); + + mBaseline = a.getDimensionPixelSize( + R.styleable.SuperImageView_baseline, -1); + + setAdjustViewBounds(a.getBoolean( + R.styleable.SuperImageView_adjustViewBounds, false)); + + setMaxWidth(a.getDimensionPixelSize( + R.styleable.SuperImageView_maxWidth, Integer.MAX_VALUE)); + + setMaxHeight(a.getDimensionPixelSize( + R.styleable.SuperImageView_maxHeight, Integer.MAX_VALUE)); + + int index = a.getInt(R.styleable.SuperImageView_scaleType, -1); + if (index >= 0) { + setScaleType(sScaleTypeArray[index]); + } + + int tint = a.getInt(R.styleable.SuperImageView_tint, 0); + if (tint != 0) { + setColorFilter(tint); + } + + int alpha = a.getInt(R.styleable.SuperImageView_drawableAlpha, 255); + if (alpha != 255) { + setAlpha(alpha); + } + + mCropToPadding = a.getBoolean(R.styleable.SuperImageView_cropToPadding, + false); + + int resId = a.getResourceId(R.styleable.SuperImageView_src, -1); + if (resId == -1) { + Drawable d = a.getDrawable(R.styleable.SuperImageView_src); + if (d != null) { + setImageDrawable(d); + } + } else + this.setImageResource(resId); + + a.recycle(); + + // need inflate syntax/reader for matrix + } + + private void initImageView() { + mMatrix = new Matrix(); + mScaleType = ScaleType.FIT_CENTER; + mAdjustViewBoundsCompat = getContext().getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; + } + + @Override + protected boolean verifyDrawable(Drawable dr) { + return mDrawable == dr || super.verifyDrawable(dr); + } + + protected boolean verifyMovie(Movie mv) { + return mMovie == mv; + } + + @SuppressLint("NewApi") + @Override + public void jumpDrawablesToCurrentState() { + if (Build.VERSION.SDK_INT < 11) { + return; + } + + super.jumpDrawablesToCurrentState(); + if (mDrawable != null) + mDrawable.jumpToCurrentState(); + } + + @Override + public void invalidateDrawable(Drawable dr) { + if (dr == mDrawable) { + /* + * we invalidate the whole view in this case because it's very hard + * to know where the drawable actually is. This is made complicated + * because of the offsets and transformations that can be applied. + * In theory we could get the drawable's bounds and run them through + * the transformation and offsets, but this is probably not worth + * the effort. + */ + invalidate(); + } else { + super.invalidateDrawable(dr); + } + } + + public void invalidateMovie(Movie mv) { + if (mv == mMovie) { + /* + * we invalidate the whole view in this case because it's very hard + * to know where the drawable actually is. This is made complicated + * because of the offsets and transformations that can be applied. + * In theory we could get the drawable's bounds and run them through + * the transformation and offsets, but this is probably not worth + * the effort. + */ + invalidate(); + } + } + + @Override + public boolean hasOverlappingRendering() { + return (getBackground() != null && getBackground().getCurrent() != null); + } + + @SuppressLint("NewApi") + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + if (Build.VERSION.SDK_INT < 14) { + return; + } + + super.onPopulateAccessibilityEvent(event); + CharSequence contentDescription = getContentDescription(); + if (!TextUtils.isEmpty(contentDescription)) { + event.getText().add(contentDescription); + } + } + + /** + * True when ImageView is adjusting its bounds to preserve the aspect ratio + * of its drawable + * + * @return whether to adjust the bounds of this view to presrve the original + * aspect ratio of the drawable + * + * @see #setAdjustViewBounds(boolean) + * + * @attr ref android.R.styleable#ImageView_adjustViewBounds + */ + public boolean getAdjustViewBounds() { + return mAdjustViewBounds; + } + + /** + * Set this to true if you want the ImageView to adjust its bounds to + * preserve the aspect ratio of its drawable. + * + *+ * Note: If the application targets API level 17 or lower, + * adjustViewBounds will allow the drawable to shrink the view bounds, but + * not grow to fill available measured space in all cases. This is for + * compatibility with legacy {@link android.view.View.MeasureSpec + * MeasureSpec} and {@link android.widget.RelativeLayout RelativeLayout} + * behavior. + *
+ * + * @param adjustViewBounds + * Whether to adjust the bounds of this view to preserve the + * original aspect ratio of the drawable. + * + * @see #getAdjustViewBounds() + * + * @attr ref android.R.styleable#ImageView_adjustViewBounds + */ + public void setAdjustViewBounds(boolean adjustViewBounds) { + mAdjustViewBounds = adjustViewBounds; + if (adjustViewBounds) { + setScaleType(ScaleType.FIT_CENTER); + } + } + + /** + * The maximum width of this view. + * + * @return The maximum width of this view + * + * @see #setMaxWidth(int) + * + * @attr ref android.R.styleable#ImageView_maxWidth + */ + public int getMaxWidth() { + return mMaxWidth; + } + + /** + * An optional argument to supply a maximum width for this view. Only valid + * if {@link #setAdjustViewBounds(boolean)} has been set to true. To set an + * image to be a maximum of 100 x 100 while preserving the original aspect + * ratio, do the following: 1) set adjustViewBounds to true 2) set maxWidth + * and maxHeight to 100 3) set the height and width layout params to + * WRAP_CONTENT. + * + *+ * Note that this view could be still smaller than 100 x 100 using this + * approach if the original image is small. To set an image to a fixed size, + * specify that size in the layout params and then use + * {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine + * how to fit the image within the bounds. + *
+ * + * @param maxWidth + * maximum width for this view + * + * @see #getMaxWidth() + * + * @attr ref android.R.styleable#ImageView_maxWidth + */ + public void setMaxWidth(int maxWidth) { + mMaxWidth = maxWidth; + } + + /** + * The maximum height of this view. + * + * @return The maximum height of this view + * + * @see #setMaxHeight(int) + * + * @attr ref android.R.styleable#ImageView_maxHeight + */ + public int getMaxHeight() { + return mMaxHeight; + } + + /** + * An optional argument to supply a maximum height for this view. Only valid + * if {@link #setAdjustViewBounds(boolean)} has been set to true. To set an + * image to be a maximum of 100 x 100 while preserving the original aspect + * ratio, do the following: 1) set adjustViewBounds to true 2) set maxWidth + * and maxHeight to 100 3) set the height and width layout params to + * WRAP_CONTENT. + * + *+ * Note that this view could be still smaller than 100 x 100 using this + * approach if the original image is small. To set an image to a fixed size, + * specify that size in the layout params and then use + * {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine + * how to fit the image within the bounds. + *
+ * + * @param maxHeight + * maximum height for this view + * + * @see #getMaxHeight() + * + * @attr ref android.R.styleable#ImageView_maxHeight + */ + public void setMaxHeight(int maxHeight) { + mMaxHeight = maxHeight; + } + + /** + * Return the view's drawable, or null if no drawable has been assigned. + */ + public Drawable getDrawable() { + return mDrawable; + } + + public int getResourceWidth() { + return mDrawableWidth; + } + + public int getResourceHeight() { + return mDrawableHeight; + } + + public Movie getMovie() { + return mMovie; + } + + public boolean isEmpty() { + if (mMovie == null && mDrawable == null) + return true; + else + return false; + } + + /** + * Sets a drawable as the content of this ImageView. + * + *+ * This does Bitmap reading and decoding on the UI thread, which can cause a + * latency hiccup. If that's a concern, consider using + * {@link #setImageDrawable(android.graphics.drawable.Drawable)} or + * {@link #setImageBitmap(android.graphics.Bitmap)} and + * {@link android.graphics.BitmapFactory} instead. + *
+ * + * @param resId + * the resource identifier of the drawable + * + * @attr ref android.R.styleable#ImageView_src + */ + public void setImageResource(int resId) { + if (mUri != null || mResource != resId) { + updateDrawable(null); + updateMovie(null); + mResource = resId; + mUri = null; + + final int oldWidth = mDrawableWidth; + final int oldHeight = mDrawableHeight; + + resolveUri(); + + if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { + requestLayout(); + } + invalidate(); + } + } + + /** + * Sets the content of this ImageView to the specified Uri. + * + *+ * This does Bitmap reading and decoding on the UI thread, which can cause a + * latency hiccup. If that's a concern, consider using + * {@link #setImageDrawable(android.graphics.drawable.Drawable)} or + * {@link #setImageBitmap(android.graphics.Bitmap)} and + * {@link android.graphics.BitmapFactory} instead. + *
+ * + * @param uri + * The Uri of an image + */ + public void setImageURI(Uri uri) { + if (mResource != 0 + || (mUri != uri && (uri == null || mUri == null || !uri + .equals(mUri)))) { + updateDrawable(null); + updateMovie(null); + mResource = 0; + mUri = uri; + + final int oldWidth = mDrawableWidth; + final int oldHeight = mDrawableHeight; + + resolveUri(); + + if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { + requestLayout(); + } + invalidate(); + } + } + + /** + * Sets a drawable as the content of this ImageView. + * + * @param drawable + * The drawable to set + */ + public void setImageDrawable(Drawable drawable) { + if (mDrawable != drawable) { + mResource = 0; + mUri = null; + mMovie = null; + + final int oldWidth = mDrawableWidth; + final int oldHeight = mDrawableHeight; + + updateDrawable(drawable); + updateMovie(null); + + if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { + requestLayout(); + } + invalidate(); + } + } + + /** + * Sets a Movie as the content of this SuperImageView. + * + * @param mv + * The movie to set + */ + public void setImageMovie(Movie mv) { + if (mMovie != mv) { + mResource = 0; + mUri = null; + mDrawable = null; + + final int oldWidth = mDrawableWidth; + final int oldHeight = mDrawableHeight; + + updateDrawable(null); + updateMovie(mv); + + if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { + requestLayout(); + } + invalidate(); + } + } + + /** + * Sets a InputStream as the content of this SuperImageView. + * + * @param is + * The InputStream to set + */ + public void setImageInputStream(InputStream is) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = is.read(buffer)) > -1) { + baos.write(buffer, 0, len); + } + is.close(); + baos.flush(); + + byte[] bytes = baos.toByteArray(); + Movie m = Movie.decodeByteArray(bytes, 0, bytes.length); + if (m == null) { + Bitmap b = BitmapFactory + .decodeByteArray(bytes, 0, bytes.length); + setImageBitmap(b); + } else + setImageMovie(m); + + baos.close(); + } catch (IOException e) { + Log.e(TAG, "Set Image from InputStream error !"); + } + } + + /** + * Sets a Bitmap as the content of this ImageView. + * + * @param bm + * The bitmap to set + */ + public void setImageBitmap(Bitmap bm) { + // if this is used frequently, may handle bitmaps explicitly + // to reduce the intermediate drawable object + setImageDrawable(new BitmapDrawable(getContext().getResources(), bm)); + } + + public void setImageState(int[] state, boolean merge) { + mState = state; + mMergeState = merge; + if (mDrawable != null) { + refreshDrawableState(); + resizeFromResource(); + } + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + resizeFromResource(); + } + + /** + * Sets the image level, when it is constructed from a + * {@link android.graphics.drawable.LevelListDrawable}. + * + * @param level + * The new level for the image. + */ + public void setImageLevel(int level) { + mLevel = level; + if (mDrawable != null) { + mDrawable.setLevel(level); + resizeFromResource(); + } + } + + /** + * Options for scaling the bounds of an image to the bounds of this view. + */ + public enum ScaleType { + /** + * Scale using the image matrix when drawing. The image matrix can be + * set using {@link SuperImageView#setImageMatrix(Matrix)}. From XML, + * use this syntax:android:scaleType="matrix".
+ */
+ MATRIX(0),
+ /**
+ * Scale the image using {@link Matrix.ScaleToFit#FILL}. From XML, use
+ * this syntax: android:scaleType="fitXY".
+ */
+ FIT_XY(1),
+ /**
+ * Scale the image using {@link Matrix.ScaleToFit#START}. From XML, use
+ * this syntax: android:scaleType="fitStart".
+ */
+ FIT_START(2),
+ /**
+ * Scale the image using {@link Matrix.ScaleToFit#CENTER}. From XML, use
+ * this syntax: android:scaleType="fitCenter".
+ */
+ FIT_CENTER(3),
+ /**
+ * Scale the image using {@link Matrix.ScaleToFit#END}. From XML, use
+ * this syntax: android:scaleType="fitEnd".
+ */
+ FIT_END(4),
+ /**
+ * Center the image in the view, but perform no scaling. From XML, use
+ * this syntax: android:scaleType="center".
+ */
+ CENTER(5),
+ /**
+ * Scale the image uniformly (maintain the image's aspect ratio) so that
+ * both dimensions (width and height) of the image will be equal to or
+ * larger than the corresponding dimension of the view (minus padding).
+ * The image is then centered in the view. From XML, use this syntax:
+ * android:scaleType="centerCrop".
+ */
+ CENTER_CROP(6),
+ /**
+ * Scale the image uniformly (maintain the image's aspect ratio) so that
+ * both dimensions (width and height) of the image will be equal to or
+ * less than the corresponding dimension of the view (minus padding).
+ * The image is then centered in the view. From XML, use this syntax:
+ * android:scaleType="centerInside".
+ */
+ CENTER_INSIDE(7);
+
+ ScaleType(int ni) {
+ nativeInt = ni;
+ }
+
+ final int nativeInt;
+ }
+
+ /**
+ * Controls how the image should be resized or moved to match the size of
+ * this ImageView.
+ *
+ * @param scaleType
+ * The desired scaling mode.
+ *
+ * @attr ref android.R.styleable#ImageView_scaleType
+ */
+ public void setScaleType(ScaleType scaleType) {
+ if (scaleType == null) {
+ throw new NullPointerException();
+ }
+
+ if (mScaleType != scaleType) {
+ mScaleType = scaleType;
+
+ setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);
+
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
+ * Return the current scale type in use by this ImageView.
+ *
+ * @see SuperImageView.ScaleType
+ *
+ * @attr ref android.R.styleable#ImageView_scaleType
+ */
+ public ScaleType getScaleType() {
+ return mScaleType;
+ }
+
+ /**
+ * Return the view's optional matrix. This is applied to the view's drawable
+ * when it is drawn. If there is not matrix, this method will return an
+ * identity matrix. Do not change this matrix in place but make a copy. If
+ * you want a different matrix applied to the drawable, be sure to call
+ * setImageMatrix().
+ */
+ public Matrix getImageMatrix() {
+ if (mDrawMatrix == null) {
+ // return new Matrix(Matrix.IDENTITY_MATRIX); //TODO Fix here
+ return new Matrix();
+ }
+ return mDrawMatrix;
+ }
+
+ public void setImageMatrix(Matrix matrix) {
+ // collaps null and identity to just null
+ if (matrix != null && matrix.isIdentity()) {
+ matrix = null;
+ }
+
+ // don't invalidate unless we're actually changing our matrix
+ if (matrix == null && !mMatrix.isIdentity() || matrix != null
+ && !mMatrix.equals(matrix)) {
+ mMatrix.set(matrix);
+ configureBounds();
+ invalidate();
+ }
+ }
+
+ /**
+ * Return whether this ImageView crops to padding.
+ *
+ * @return whether this ImageView crops to padding
+ *
+ * @see #setCropToPadding(boolean)
+ *
+ * @attr ref android.R.styleable#ImageView_cropToPadding
+ */
+ public boolean getCropToPadding() {
+ return mCropToPadding;
+ }
+
+ /**
+ * Sets whether this ImageView will crop to padding.
+ *
+ * @param cropToPadding
+ * whether this ImageView will crop to padding
+ *
+ * @see #getCropToPadding()
+ *
+ * @attr ref android.R.styleable#ImageView_cropToPadding
+ */
+ public void setCropToPadding(boolean cropToPadding) {
+ if (mCropToPadding != cropToPadding) {
+ mCropToPadding = cropToPadding;
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ private void resolveUri() {
+ if (mDrawable != null && mMovie != null) {
+ return;
+ }
+
+ Resources rsrc = getResources();
+ if (rsrc == null) {
+ return;
+ }
+
+ Drawable d = null;
+ Movie m = null;
+
+ if (mResource != 0) {
+ try {
+ InputStream is = rsrc.openRawResource(mResource);
+ m = Movie.decodeStream(is);
+ if (m == null) {
+ d = rsrc.getDrawable(mResource);
+ }
+ } catch (Exception e) {
+ Log.w("ImageView", "Unable to find resource: " + mResource, e);
+ // Don't try again.
+ mUri = null;
+ }
+ } else if (mUri != null) {
+ String scheme = mUri.getScheme();
+ /*
+ * if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) { //
+ * TODO Can't fix here try { // Load drawable through Resources, to
+ * get the source density information
+ * ContentResolver.OpenResourceIdResult r =
+ * getContext().getContentResolver().getResourceId(mUri); d =
+ * r.r.getDrawable(r.id); } catch (Exception e) { Log.w("ImageView",
+ * "Unable to open content: " + mUri, e); } } else
+ */if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+ || ContentResolver.SCHEME_FILE.equals(scheme)) {
+ InputStream stream = null;
+ try {
+ stream = getContext().getContentResolver().openInputStream(
+ mUri);
+ m = Movie.decodeStream(stream);
+ if (m == null) {
+ stream = getContext().getContentResolver()
+ .openInputStream(mUri);
+ d = Drawable.createFromStream(stream, null);
+ }
+ } catch (Exception e) {
+ Log.w("ImageView", "Unable to open content: " + mUri, e);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ Log.w("ImageView", "Unable to close content: "
+ + mUri, e);
+ }
+ }
+ }
+ } else {
+ d = Drawable.createFromPath(mUri.toString());
+ }
+ if (d == null && m == null) {
+ System.out.println("resolveUri failed on bad bitmap uri: "
+ + mUri);
+ // Don't try again.
+ mUri = null;
+ }
+ } else {
+ return;
+ }
+
+ updateDrawable(d);
+ updateMovie(m);
+ }
+
+ @Override
+ public int[] onCreateDrawableState(int extraSpace) {
+ if (mState == null) {
+ return super.onCreateDrawableState(extraSpace);
+ } else if (!mMergeState) {
+ return mState;
+ } else {
+ return mergeDrawableStates(
+ super.onCreateDrawableState(extraSpace + mState.length),
+ mState);
+ }
+ }
+
+ private void updateDrawable(Drawable d) {
+ if (mDrawable != null) {
+ mDrawable.setCallback(null);
+ unscheduleDrawable(mDrawable);
+ }
+ mDrawable = d;
+ if (d != null) {
+ d.setCallback(this);
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ d.setLevel(mLevel);
+ // d.setLayoutDirection(getLayoutDirection()); // TODO Can't fix, reflection?
+ // here
+ d.setVisible(getVisibility() == VISIBLE, true);
+ mDrawableWidth = d.getIntrinsicWidth();
+ mDrawableHeight = d.getIntrinsicHeight();
+ applyColorMod();
+ configureBounds();
+ } else {
+ mDrawableWidth = mDrawableHeight = -1;
+ }
+ }
+
+ private void updateMovie(Movie m) {
+ mMovie = m;
+ if (m != null) {
+ mMovieStart = 0;
+ mCurrentAnimationTime = 0;
+ mDrawableWidth = m.width();
+ mDrawableHeight = m.height();
+ applyColorMod();
+ configureBounds();
+ }
+ }
+
+ private void resizeFromResource() {
+ Drawable d = mDrawable;
+ Movie m = mMovie;
+ if (d != null) {
+ int w = d.getIntrinsicWidth();
+ if (w < 0)
+ w = mDrawableWidth;
+ int h = d.getIntrinsicHeight();
+ if (h < 0)
+ h = mDrawableHeight;
+ if (w != mDrawableWidth || h != mDrawableHeight) {
+ mDrawableWidth = w;
+ mDrawableHeight = h;
+ requestLayout();
+ }
+ } else if (m != null) {
+ int w = m.width();
+ if (w < 0)
+ w = mDrawableWidth;
+ int h = m.height();
+ if (h < 0)
+ h = mDrawableHeight;
+ if (w != mDrawableWidth || h != mDrawableHeight) {
+ mDrawableWidth = w;
+ mDrawableHeight = h;
+ requestLayout();
+ }
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ if (Build.VERSION.SDK_INT < 17) {
+ return;
+ }
+
+ super.onRtlPropertiesChanged(layoutDirection);
+
+ if (mDrawable != null) {
+ // mDrawable.setLayoutDirection(layoutDirection); // TODO Can't fix, reflection?
+ // here
+ }
+ }
+
+ private static final Matrix.ScaleToFit[] sS2FArray = {
+ Matrix.ScaleToFit.FILL, Matrix.ScaleToFit.START,
+ Matrix.ScaleToFit.CENTER, Matrix.ScaleToFit.END };
+
+ private static Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType st) {
+ // ScaleToFit enum to their corresponding Matrix.ScaleToFit values
+ return sS2FArray[st.nativeInt - 1];
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ resolveUri();
+ int w;
+ int h;
+
+ // Desired aspect ratio of the view's contents (not including padding)
+ float desiredAspect = 0.0f;
+
+ // We are allowed to change the view's width
+ boolean resizeWidth = false;
+
+ // We are allowed to change the view's height
+ boolean resizeHeight = false;
+
+ final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
+ if (mDrawable == null && mMovie == null) {
+ // If no drawable, its intrinsic size is 0.
+ mDrawableWidth = -1;
+ mDrawableHeight = -1;
+ w = h = 0;
+ } else {
+ w = mDrawableWidth;
+ h = mDrawableHeight;
+ if (w <= 0)
+ w = 1;
+ if (h <= 0)
+ h = 1;
+
+ // We are supposed to adjust view bounds to match the aspect
+ // ratio of our drawable. See if that is possible.
+ if (mAdjustViewBounds) {
+ resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
+ resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
+
+ desiredAspect = (float) w / (float) h;
+ }
+ }
+
+ int pleft = getPaddingLeft();
+ int pright = getPaddingRight();
+ int ptop = getPaddingTop();
+ int pbottom = getPaddingBottom();
+
+ int widthSize;
+ int heightSize;
+
+ if (resizeWidth || resizeHeight) {
+ /*
+ * If we get here, it means we want to resize to match the drawables
+ * aspect ratio, and we have the freedom to change at least one
+ * dimension.
+ */
+
+ // Get the max possible width given our constraints
+ widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth,
+ widthMeasureSpec);
+
+ // Get the max possible height given our constraints
+ heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight,
+ heightMeasureSpec);
+
+ if (desiredAspect != 0.0f) {
+ // See what our actual aspect ratio is
+ float actualAspect = (float) (widthSize - pleft - pright)
+ / (heightSize - ptop - pbottom);
+
+ if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
+
+ boolean done = false;
+
+ // Try adjusting width to be proportional to height
+ if (resizeWidth) {
+ int newWidth = (int) (desiredAspect * (heightSize
+ - ptop - pbottom))
+ + pleft + pright;
+
+ // Allow the width to outgrow its original estimate if
+ // height is fixed.
+ if (!resizeHeight && !mAdjustViewBoundsCompat) {
+ widthSize = resolveAdjustedSize(newWidth,
+ mMaxWidth, widthMeasureSpec);
+ }
+
+ if (newWidth <= widthSize) {
+ widthSize = newWidth;
+ done = true;
+ }
+ }
+
+ // Try adjusting height to be proportional to width
+ if (!done && resizeHeight) {
+ int newHeight = (int) ((widthSize - pleft - pright) / desiredAspect)
+ + ptop + pbottom;
+
+ // Allow the height to outgrow its original estimate if
+ // width is fixed.
+ if (!resizeWidth && !mAdjustViewBoundsCompat) {
+ heightSize = resolveAdjustedSize(newHeight,
+ mMaxHeight, heightMeasureSpec);
+ }
+
+ if (newHeight <= heightSize) {
+ heightSize = newHeight;
+ }
+ }
+ }
+ }
+ } else {
+ /*
+ * We are either don't want to preserve the drawables aspect ratio,
+ * or we are not allowed to change view dimensions. Just measure in
+ * the normal way.
+ */
+ w += pleft + pright;
+ h += ptop + pbottom;
+
+ w = Math.max(w, getSuggestedMinimumWidth());
+ h = Math.max(h, getSuggestedMinimumHeight());
+
+ if (Build.VERSION.SDK_INT < 11) {
+ widthSize = resolveSize(w, widthMeasureSpec);
+ heightSize = resolveSize(h, heightMeasureSpec);
+ } else {
+ widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
+ heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
+ }
+ }
+
+ setMeasuredDimension(widthSize, heightSize);
+ }
+
+ private int resolveAdjustedSize(int desiredSize, int maxSize,
+ int measureSpec) {
+ int result = desiredSize;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+ switch (specMode) {
+ case MeasureSpec.UNSPECIFIED:
+ /*
+ * Parent says we can be as big as we want. Just don't be larger
+ * than max size imposed on ourselves.
+ */
+ result = Math.min(desiredSize, maxSize);
+ break;
+ case MeasureSpec.AT_MOST:
+ // Parent says we can be as big as we want, up to specSize.
+ // Don't be larger than specSize, and don't be larger than
+ // the max size imposed on ourselves.
+ result = Math.min(Math.min(desiredSize, specSize), maxSize);
+ break;
+ case MeasureSpec.EXACTLY:
+ // No choice. Do what we are told.
+ result = specSize;
+ break;
+ }
+ return result;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right,
+ int bottom) {
+ configureBounds();
+ }
+
+ private void configureBounds() {
+ if (mDrawable == null && mMovie == null) {
+ return;
+ }
+
+ int dwidth = mDrawableWidth;
+ int dheight = mDrawableHeight;
+
+ int vwidth = getWidth() - getPaddingLeft() - getPaddingRight();
+ int vheight = getHeight() - getPaddingTop() - getPaddingBottom();
+
+ boolean fits = (dwidth < 0 || vwidth == dwidth)
+ && (dheight < 0 || vheight == dheight);
+
+ if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
+ /*
+ * If the drawable has no intrinsic size, or we're told to
+ * scaletofit, then we just fill our entire view.
+ */
+ if (mDrawable != null) {
+ mDrawable.setBounds(0, 0, vwidth, vheight);
+ mDrawMatrix = null;
+ } else if (dheight > 0 && dheight > 0) {
+ mDrawMatrix = new Matrix();
+ mDrawMatrix.setScale((float) vwidth / dwidth, (float) vheight
+ / dheight);
+ }
+
+ } else {
+ // We need to do the scaling ourself, so have the drawable
+ // use its native size.
+ if (mDrawable != null)
+ mDrawable.setBounds(0, 0, dwidth, dheight);
+
+ if (ScaleType.MATRIX == mScaleType) {
+ // Use the specified matrix as-is.
+ if (mMatrix.isIdentity()) {
+ mDrawMatrix = null;
+ } else {
+ mDrawMatrix = mMatrix;
+ }
+ } else if (fits) {
+ // The bitmap fits exactly, no transform needed.
+ mDrawMatrix = null;
+ } else if (ScaleType.CENTER == mScaleType) {
+ // Center bitmap in view, no scaling.
+ mDrawMatrix = mMatrix;
+ mDrawMatrix.setTranslate(
+ (int) ((vwidth - dwidth) * 0.5f + 0.5f),
+ (int) ((vheight - dheight) * 0.5f + 0.5f));
+ } else if (ScaleType.CENTER_CROP == mScaleType) {
+ mDrawMatrix = mMatrix;
+
+ float scale;
+ float dx = 0, dy = 0;
+
+ if (dwidth * vheight > vwidth * dheight) {
+ scale = (float) vheight / (float) dheight;
+ dx = (vwidth - dwidth * scale) * 0.5f;
+ } else {
+ scale = (float) vwidth / (float) dwidth;
+ dy = (vheight - dheight * scale) * 0.5f;
+ }
+
+ mDrawMatrix.setScale(scale, scale);
+ mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
+ } else if (ScaleType.CENTER_INSIDE == mScaleType) {
+ mDrawMatrix = mMatrix;
+ float scale;
+ float dx;
+ float dy;
+
+ if (dwidth <= vwidth && dheight <= vheight) {
+ scale = 1.0f;
+ } else {
+ scale = Math.min((float) vwidth / (float) dwidth,
+ (float) vheight / (float) dheight);
+ }
+
+ dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
+ dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);
+
+ mDrawMatrix.setScale(scale, scale);
+ mDrawMatrix.postTranslate(dx, dy);
+ } else {
+ // Generate the required transform.
+ mTempSrc.set(0, 0, dwidth, dheight);
+ mTempDst.set(0, 0, vwidth, vheight);
+
+ mDrawMatrix = mMatrix;
+ mDrawMatrix.setRectToRect(mTempSrc, mTempDst,
+ scaleTypeToScaleToFit(mScaleType));
+ }
+ }
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ Drawable d = mDrawable;
+ if (d != null && d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mDrawable == null && mMovie == null) {
+ return; // couldn't resolve the URI
+ }
+
+ if (mDrawableWidth == 0 || mDrawableHeight == 0) {
+ return; // nothing to draw (empty bounds)
+ }
+
+ int pLeft = getPaddingLeft();
+
+ if (mDrawMatrix == null && getPaddingTop() == 0 && pLeft == 0) {
+ if (mDrawable != null)
+ mDrawable.draw(canvas);
+ else
+ drawMovieFrame(canvas);
+ } else {
+ int saveCount = canvas.getSaveCount();
+ canvas.save();
+
+ if (mCropToPadding) {
+ final int scrollX = getScrollX();
+ final int scrollY = getScrollY();
+ canvas.clipRect(scrollX + pLeft, scrollY + getPaddingTop(),
+ scrollX + getRight() - getLeft() - getPaddingRight(), scrollY
+ + getBottom() - getTop() - getPaddingBottom());
+ }
+
+ canvas.translate(pLeft, getPaddingTop());
+
+ if (mDrawMatrix != null) {
+ canvas.concat(mDrawMatrix);
+ }
+ if (mDrawable != null)
+ mDrawable.draw(canvas);
+ else
+ drawMovieFrame(canvas);
+ canvas.restoreToCount(saveCount);
+ }
+ }
+
+ @SuppressLint("NewApi")
+ private void drawMovieFrame(Canvas canvas) {
+ // if (!mPaused)
+ updateAnimationTime();
+
+ mMovie.setTime(mCurrentAnimationTime);
+ mMovie.draw(canvas, 0, 0);
+
+ // if (!mPaused)
+ if (Build.VERSION.SDK_INT < 16) {
+ invalidate();
+ } else {
+ postInvalidateOnAnimation();
+ }
+ }
+
+ private void updateAnimationTime() {
+ long now = android.os.SystemClock.uptimeMillis();
+
+ if (mMovieStart == 0) {
+ mMovieStart = now;
+ }
+
+ int dur = mMovie.duration();
+
+ if (dur == 0) {
+ dur = DEFAULT_MOVIEW_DURATION;
+ }
+
+ mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
+ }
+
+ /**
+ * + * Return the offset of the widget's text baseline from the widget's top + * boundary. + *
+ * + * @return the offset of the baseline within the widget's bounds or -1 if + * baseline alignment is not supported. + */ + @Override + @ViewDebug.ExportedProperty(category = "layout") + public int getBaseline() { + if (mBaselineAlignBottom) { + return getMeasuredHeight(); + } else { + return mBaseline; + } + } + + /** + *+ * Set the offset of the widget's text baseline from the widget's top + * boundary. This value is overridden by the + * {@link #setBaselineAlignBottom(boolean)} property. + *
+ * + * @param baseline + * The baseline to use, or -1 if none is to be provided. + * + * @see #setBaseline(int) + * @attr ref android.R.styleable#ImageView_baseline + */ + public void setBaseline(int baseline) { + if (mBaseline != baseline) { + mBaseline = baseline; + requestLayout(); + } + } + + /** + * Set whether to set the baseline of this view to the bottom of the view. + * Setting this value overrides any calls to setBaseline. + * + * @param aligned + * If true, the image view will be baseline aligned with based on + * its bottom edge. + * + * @attr ref android.R.styleable#ImageView_baselineAlignBottom + */ + public void setBaselineAlignBottom(boolean aligned) { + if (mBaselineAlignBottom != aligned) { + mBaselineAlignBottom = aligned; + requestLayout(); + } + } + + /** + * Return whether this view's baseline will be considered the bottom of the + * view. + * + * @see #setBaselineAlignBottom(boolean) + */ + public boolean getBaselineAlignBottom() { + return mBaselineAlignBottom; + } + + /** + * Set a tinting option for the image. + * + * @param color + * Color tint to apply. + * @param mode + * How to apply the color. The standard mode is + * {@link PorterDuff.Mode#SRC_ATOP} + * + * @attr ref android.R.styleable#ImageView_tint + */ + public final void setColorFilter(int color, PorterDuff.Mode mode) { + setColorFilter(new PorterDuffColorFilter(color, mode)); + } + + /** + * Set a tinting option for the image. Assumes + * {@link PorterDuff.Mode#SRC_ATOP} blending mode. + * + * @param color + * Color tint to apply. + * @attr ref android.R.styleable#ImageView_tint + */ + public final void setColorFilter(int color) { + setColorFilter(color, PorterDuff.Mode.SRC_ATOP); + } + + public final void clearColorFilter() { + setColorFilter(null); + } + + /** + * @hide Candidate for future API inclusion + */ + public final void setXfermode(Xfermode mode) { + if (mXfermode != mode) { + mXfermode = mode; + mColorMod = true; + applyColorMod(); + invalidate(); + } + } + + /** + * Returns the active color filter for this ImageView. + * + * @return the active color filter for this ImageView + * + * @see #setColorFilter(android.graphics.ColorFilter) + */ + public ColorFilter getColorFilter() { + return mColorFilter; + } + + /** + * Apply an arbitrary colorfilter to the image. + * + * @param cf + * the colorfilter to apply (may be null) + * + * @see #getColorFilter() + */ + public void setColorFilter(ColorFilter cf) { + if (mColorFilter != cf) { + mColorFilter = cf; + mColorMod = true; + applyColorMod(); + invalidate(); + } + } + + /** + * Returns the alpha that will be applied to the drawable of this ImageView. + * + * @return the alpha that will be applied to the drawable of this ImageView + * + * @see #setImageAlpha(int) + */ + public int getImageAlpha() { + return mAlpha; + } + + /** + * Sets the alpha value that should be applied to the image. + * + * @param alpha + * the alpha value that should be applied to the image + * + * @see #getImageAlpha() + */ + public void setImageAlpha(int alpha) { + setAlpha(alpha); + } + + /** + * Sets the alpha value that should be applied to the image. + * + * @param alpha + * the alpha value that should be applied to the image + * + * @deprecated use #setImageAlpha(int) instead + */ + @Deprecated + public void setAlpha(int alpha) { + alpha &= 0xFF; // keep it legal + if (mAlpha != alpha) { + mAlpha = alpha; + mColorMod = true; + applyColorMod(); + invalidate(); + } + } + + private void applyColorMod() { + // Only mutate and apply when modifications have occurred. This should + // not reset the mColorMod flag, since these filters need to be + // re-applied if the Drawable is changed. + if (mDrawable != null && mColorMod) { + mDrawable = mDrawable.mutate(); + mDrawable.setColorFilter(mColorFilter); + // mDrawable.setXfermode(mXfermode); // Can't fix here + mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8); + } + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (mDrawable != null) { + mDrawable.setVisible(visibility == VISIBLE, false); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mDrawable != null) { + mDrawable.setVisible(getVisibility() == VISIBLE, false); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mDrawable != null) { + mDrawable.setVisible(false, false); + } + } + + @SuppressLint("NewApi") + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + if (Build.VERSION.SDK_INT < 14) { + return; + } + + super.onInitializeAccessibilityEvent(event); + event.setClassName(SuperImageView.class.getName()); + } + + @SuppressLint("NewApi") + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + if (Build.VERSION.SDK_INT < 14) { + return; + } + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(SuperImageView.class.getName()); + } } \ No newline at end of file diff --git a/src/com/hippo/ehviewer/widget/AutoWrapLayout.java b/src/com/hippo/ehviewer/widget/AutoWrapLayout.java index ab19575ae..3a2981732 100644 --- a/src/com/hippo/ehviewer/widget/AutoWrapLayout.java +++ b/src/com/hippo/ehviewer/widget/AutoWrapLayout.java @@ -10,7 +10,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.View; import android.view.ViewGroup; diff --git a/src/com/hippo/ehviewer/widget/DrawerLayout.java b/src/com/hippo/ehviewer/widget/DrawerLayout.java index c0cf6082e..cba72ceb7 100644 --- a/src/com/hippo/ehviewer/widget/DrawerLayout.java +++ b/src/com/hippo/ehviewer/widget/DrawerLayout.java @@ -35,7 +35,7 @@ import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewGroupCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.util.AttributeSet; -import android.util.Log; +import com.hippo.ehviewer.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; diff --git a/src/com/jakewharton/disklrucache/DiskLruCache.java b/src/com/jakewharton/disklrucache/DiskLruCache.java index d5f543005..4ae961c19 100644 --- a/src/com/jakewharton/disklrucache/DiskLruCache.java +++ b/src/com/jakewharton/disklrucache/DiskLruCache.java @@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -import android.util.Log; +import com.hippo.ehviewer.util.Log; /** * A cache that uses a bounded amount of space on a filesystem. Each cache entry