diff --git a/bin/EhViewer.apk b/bin/EhViewer.apk index c83546da3..1218af005 100644 Binary files a/bin/EhViewer.apk and b/bin/EhViewer.apk differ diff --git a/bin/classes.dex b/bin/classes.dex index 8de49aa47..2c1d53edc 100644 Binary files a/bin/classes.dex and b/bin/classes.dex differ diff --git a/bin/dexedLibs/gridlayout_v7-9aadecd3606a07a44286cb470164fa04.jar b/bin/dexedLibs/gridlayout_v7-9aadecd3606a07a44286cb470164fa04.jar index 008b4d683..4ce072043 100644 Binary files a/bin/dexedLibs/gridlayout_v7-9aadecd3606a07a44286cb470164fa04.jar and b/bin/dexedLibs/gridlayout_v7-9aadecd3606a07a44286cb470164fa04.jar differ diff --git a/bin/res/crunch/drawable-hdpi/gamecg.png b/bin/res/crunch/drawable-hdpi/gamecg.png index a6fae72d7..dee4326de 100644 Binary files a/bin/res/crunch/drawable-hdpi/gamecg.png and b/bin/res/crunch/drawable-hdpi/gamecg.png differ diff --git a/bin/res/crunch/drawable-mdpi/gamecg.png b/bin/res/crunch/drawable-mdpi/gamecg.png index af91cfaed..a5e0f4184 100644 Binary files a/bin/res/crunch/drawable-mdpi/gamecg.png and b/bin/res/crunch/drawable-mdpi/gamecg.png differ diff --git a/bin/res/crunch/drawable-xhdpi/gamecg.png b/bin/res/crunch/drawable-xhdpi/gamecg.png index 43a76590f..7994142d4 100644 Binary files a/bin/res/crunch/drawable-xhdpi/gamecg.png and b/bin/res/crunch/drawable-xhdpi/gamecg.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/gamecg.png b/bin/res/crunch/drawable-xxhdpi/gamecg.png index 47838c882..c6d399c9d 100644 Binary files a/bin/res/crunch/drawable-xxhdpi/gamecg.png and b/bin/res/crunch/drawable-xxhdpi/gamecg.png differ diff --git a/bin/resources.ap_ b/bin/resources.ap_ index 8e1577582..ecaad383b 100644 Binary files a/bin/resources.ap_ and b/bin/resources.ap_ differ diff --git a/res/drawable-hdpi/gamecg.png b/res/drawable-hdpi/gamecg.png index 870c4dbfc..e8528d3d6 100644 Binary files a/res/drawable-hdpi/gamecg.png and b/res/drawable-hdpi/gamecg.png differ diff --git a/res/drawable-mdpi/gamecg.png b/res/drawable-mdpi/gamecg.png index 0de0d3e86..65c318b56 100644 Binary files a/res/drawable-mdpi/gamecg.png and b/res/drawable-mdpi/gamecg.png differ diff --git a/res/drawable-xhdpi/gamecg.png b/res/drawable-xhdpi/gamecg.png index efbb2d097..041698b01 100644 Binary files a/res/drawable-xhdpi/gamecg.png and b/res/drawable-xhdpi/gamecg.png differ diff --git a/res/drawable-xxhdpi/gamecg.png b/res/drawable-xxhdpi/gamecg.png index 3baaddec9..d025d2534 100644 Binary files a/res/drawable-xxhdpi/gamecg.png and b/res/drawable-xxhdpi/gamecg.png differ diff --git a/res/layout/list_item.xml b/res/layout/list_item.xml index 7ec2f953a..8fc565205 100644 --- a/res/layout/list_item.xml +++ b/res/layout/list_item.xml @@ -1,14 +1,12 @@ - diff --git a/res/raw/change_log b/res/raw/change_log index 144d44ca9..cc959580b 100644 --- a/res/raw/change_log +++ b/res/raw/change_log @@ -7,6 +7,7 @@ Version 0.3.2 (2014-??-??) * 后台检查登陆状态 * 设置中添加移除所有应用通知项 * 修正清除缓存错误 +* 修正 game 拼写为 gmae 错误 * 修正其他问题 Version 0.3.1 (2014-03-14) diff --git a/src/com/hippo/ehviewer/ImageLoadManager.java b/src/com/hippo/ehviewer/ImageLoadManager.java new file mode 100644 index 000000000..d5b7f0433 --- /dev/null +++ b/src/com/hippo/ehviewer/ImageLoadManager.java @@ -0,0 +1,153 @@ +package com.hippo.ehviewer; + +import java.util.Stack; + +import com.hippo.ehviewer.network.HttpHelper; +import com.hippo.ehviewer.util.Ui; +import com.hippo.ehviewer.util.Util; +import com.hippo.ehviewer.widget.LoadImageView; + +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Message; +import android.support.v4.util.LruCache; + +public class ImageLoadManager { + + private class LoadTask { + public LoadImageView liv; + public boolean download; + public Bitmap bitmap; + + public LoadTask(LoadImageView liv, boolean download) { + this.liv = liv; + this.download = download; + } + } + + private final Stack mLoadCacheTask; + private ImageDownloadManager mImageDownloadTask; + + private LruCache mMemoryCache; + private DiskCache mDiskCache; + + private LoadTask curLoadTask; + private final LoadTask emptyLoadTask = new LoadTask(null, false); + + private static final Handler loadImageHandler = + new Handler() { + @Override + public void handleMessage(Message msg) { + LoadTask task = (LoadTask)msg.obj; + task.liv.setImageBitmap(task.bitmap); + } + }; + + public ImageLoadManager(LruCache memoryCache, + DiskCache diskCache) { + mLoadCacheTask = new Stack(); + mImageDownloadTask = new ImageDownloadManager(); + + mMemoryCache = memoryCache; + mDiskCache = diskCache; + } + + public synchronized void add(LoadImageView liv, boolean download) { + liv.setState(LoadImageView.LOADING); + mLoadCacheTask.push(new LoadTask(liv, download)); + if (curLoadTask == null) { + new Thread(new LoadFromCacheTask()).start(); + curLoadTask = emptyLoadTask; + } + } + + private class LoadFromCacheTask implements Runnable { + @Override + public void run() { + while (true) { + synchronized (ImageLoadManager.this) { + if (mLoadCacheTask.isEmpty()) { + curLoadTask = null; + break; + } + curLoadTask = mLoadCacheTask.pop(); + } + LoadImageView liv = curLoadTask.liv; + String key = liv.getKey(); + Bitmap bitmap; + if ((bitmap = mMemoryCache.get(key)) == null) { + bitmap = (Bitmap)mDiskCache.get(key, Util.BITMAP); + if (bitmap != null) + mMemoryCache.put(key, bitmap); + } + + Message msg = new Message(); + msg.obj = curLoadTask; + if (bitmap == null) { // Load from cache error + curLoadTask.bitmap = Ui.BITMAP_LAUNCH; + if (curLoadTask.download) + mImageDownloadTask.add(curLoadTask); + else + liv.setState(LoadImageView.FAIL); + } else { + curLoadTask.bitmap = bitmap; + liv.setState(LoadImageView.LOADED); + } + loadImageHandler.sendMessage(msg); + } + } + } + + private class ImageDownloadManager { + private static final int MAX_DOWNLOAD_THREADS = 3; + + private final Stack mDownloadTask; + + private int workingDownloadThreads = 0; + + public ImageDownloadManager() { + mDownloadTask = new Stack(); + } + + public synchronized void add(LoadTask loadTask) { + mDownloadTask.push(loadTask); + if (workingDownloadThreads < MAX_DOWNLOAD_THREADS) { + new Thread(new DownloadImageTask()).start(); + workingDownloadThreads++; + } + } + + private class DownloadImageTask implements Runnable { + @Override + public void run() { + LoadTask loadTask; + HttpHelper httpHelper = new HttpHelper(); + while (true) { + synchronized (ImageDownloadManager.this) { + if (mDownloadTask.isEmpty()) { + loadTask = null; + workingDownloadThreads--; + break; + } + loadTask = mDownloadTask.pop(); + } + LoadImageView liv = loadTask.liv; + Bitmap bitmap = httpHelper.getImage(liv.getUrl(), + liv.getKey(), mMemoryCache, mDiskCache, true); + + Message msg = new Message(); + msg.obj = loadTask; + if (bitmap == null) { + loadTask.bitmap = Ui.BITMAP_TOUCH; + liv.setState(LoadImageView.FAIL); + liv.setOnClickListener(ImageLoadManager.this); + } else { + loadTask.bitmap = bitmap; + liv.setState(LoadImageView.LOADED); + } + loadImageHandler.sendMessage(msg); + } + } + } + } +} diff --git a/src/com/hippo/ehviewer/activity/MangaListActivity.java b/src/com/hippo/ehviewer/activity/MangaListActivity.java index fcbb3719f..5bb23829b 100644 --- a/src/com/hippo/ehviewer/activity/MangaListActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaListActivity.java @@ -1,17 +1,15 @@ package com.hippo.ehviewer.activity; -import java.io.File; -import java.net.MalformedURLException; import java.util.ArrayList; import com.hippo.ehviewer.BeautifyScreen; +import com.hippo.ehviewer.ImageLoadManager; import com.hippo.ehviewer.ListMangaDetail; import com.hippo.ehviewer.ListUrls; import com.hippo.ehviewer.R; import com.hippo.ehviewer.UpdateHelper; import com.hippo.ehviewer.dialog.DialogBuilder; import com.hippo.ehviewer.dialog.SuperDialogUtil; -import com.hippo.ehviewer.network.Downloader; import com.hippo.ehviewer.service.DownloadService; import com.hippo.ehviewer.service.DownloadServiceConnection; import com.hippo.ehviewer.util.Cache; @@ -23,28 +21,24 @@ import com.hippo.ehviewer.util.Ui; import com.hippo.ehviewer.view.AlertButton; import com.hippo.ehviewer.view.CheckImage; import com.hippo.ehviewer.view.GetPaddingRelativeLayout; -import com.hippo.ehviewer.view.OlImageView; import com.hippo.ehviewer.view.TagListView; import com.hippo.ehviewer.view.TagsAdapter; import com.hippo.ehviewer.widget.DrawerLayout; +import com.hippo.ehviewer.widget.LoadImageView; import com.hippo.ehviewer.widget.PullListView; import com.hippo.ehviewer.widget.PullListView.OnFooterRefreshListener; import com.hippo.ehviewer.widget.PullListView.OnHeaderRefreshListener; -import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; -import android.app.NotificationManager; import android.app.SearchManager; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; -import android.support.v4.app.NotificationCompat; -import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; @@ -77,6 +71,7 @@ import android.widget.Toast; // TODO add lock to get list public class MangaListActivity extends Activity { + @SuppressWarnings("unused") private static String TAG = "MangaListActivity"; private DrawerLayout drawer; @@ -106,7 +101,10 @@ public class MangaListActivity extends Activity { private int mStableItemCount; private ArrayList lmdArray = new ArrayList(); - + + private ImageLoadManager mImageLoadManager; + + private int longClickItemIndex; private boolean mListFirst = true; @@ -134,7 +132,6 @@ public class MangaListActivity extends Activity { private int visiblePage = 0; private String title; - private String updateFileName; private class RefreshPackage { public ListUrls listUrls; @@ -897,8 +894,12 @@ public class MangaListActivity extends Activity { int getChildCount = view.getChildCount(); for (int i = 0; i < getChildCount; i++) { View v = ((ViewGroup) view.getChildAt(i)).getChildAt(0); - if (v instanceof OlImageView) - ((OlImageView)v).loadImage(false); + if (v instanceof LoadImageView) { + LoadImageView liv = (LoadImageView)v; + int status = liv.getState(); + if (status != LoadImageView.LOADING && status != LoadImageView.LOADED) + mImageLoadManager.add(liv, true); + } } mListFirst = false; } @@ -930,8 +931,12 @@ public class MangaListActivity extends Activity { && (getChildCount = view.getChildCount()) != 0) { for (int i = 0; i < getChildCount; i++) { View v = ((ViewGroup) view.getChildAt(i)).getChildAt(0); - if (v instanceof OlImageView) - ((OlImageView) v).loadImage(false); + if (v instanceof LoadImageView) { + LoadImageView liv = (LoadImageView)v; + int status = liv.getState(); + if (status != LoadImageView.LOADING && status != LoadImageView.LOADED) + mImageLoadManager.add(liv, true); + } } } } @@ -965,12 +970,10 @@ public class MangaListActivity extends Activity { if (convertView == null) convertView = mInflater.inflate(R.layout.list_item, null); - OlImageView thumb = (OlImageView)convertView.findViewById(R.id.cover); + LoadImageView thumb = (LoadImageView)convertView.findViewById(R.id.cover); if (!lmd.gid.equals(thumb.getKey())) { - thumb.setUrl(lmd.thumb); - thumb.setKey(lmd.gid); - thumb.setCache(Cache.memoryCache, Cache.cpCache); - thumb.loadFromCache(); + thumb.setLoadInfo(lmd.thumb, lmd.gid); + mImageLoadManager.add(thumb, false); // Set manga name TextView name = (TextView) convertView.findViewById(R.id.name); @@ -1031,6 +1034,9 @@ public class MangaListActivity extends Activity { filterDialog = createFilterDialog(); longClickDialog = createLongClickDialog(); + // + mImageLoadManager = new ImageLoadManager(Cache.memoryCache, Cache.cpCache); + getActionBar().setDisplayHomeAsUpEnabled(true); // For colourfy the activity @@ -1501,10 +1507,6 @@ public class MangaListActivity extends Activity { loginDialog.show(); } - class ImageLoadTask { - - } - diff --git a/src/com/hippo/ehviewer/activity/SettingsActivity.java b/src/com/hippo/ehviewer/activity/SettingsActivity.java index 20b5caee3..e7c6cd368 100644 --- a/src/com/hippo/ehviewer/activity/SettingsActivity.java +++ b/src/com/hippo/ehviewer/activity/SettingsActivity.java @@ -1,9 +1,6 @@ package com.hippo.ehviewer.activity; -import java.io.BufferedReader; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import com.hippo.ehviewer.BeautifyScreen; import com.hippo.ehviewer.DiskCache; @@ -20,7 +17,6 @@ import android.annotation.SuppressLint; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.net.Uri; @@ -33,15 +29,12 @@ import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; import android.support.v4.util.LruCache; -import android.text.Html; -import android.util.Log; import android.webkit.WebView; -import android.widget.ScrollView; -import android.widget.TextView; import android.widget.Toast; //TODO Add thanks public class SettingsActivity extends PreferenceActivity { + @SuppressWarnings("unused") private static String TAG = "Settings"; private Context mContext; @@ -86,6 +79,7 @@ public class SettingsActivity extends PreferenceActivity { setRequestedOrientation(screenOri); } + @SuppressWarnings("deprecation") @SuppressLint("NewApi") @Override public void onCreate(Bundle savedInstanceState) { diff --git a/src/com/hippo/ehviewer/network/Downloader.java b/src/com/hippo/ehviewer/network/Downloader.java index 500e698b7..b835cc33c 100644 --- a/src/com/hippo/ehviewer/network/Downloader.java +++ b/src/com/hippo/ehviewer/network/Downloader.java @@ -33,7 +33,7 @@ public class Downloader implements Runnable { private static final int MAX_REDIRECTS = 5; private static final int MAX_RETRY = 5; - private static final int DEFAULT_TIMEOUT = 20 * 1000; + private static final int DEFAULT_TIMEOUT = 5 * 1000; private String mPath; private String mFileName; diff --git a/src/com/hippo/ehviewer/network/HttpHelper.java b/src/com/hippo/ehviewer/network/HttpHelper.java new file mode 100644 index 000000000..0da2d1b18 --- /dev/null +++ b/src/com/hippo/ehviewer/network/HttpHelper.java @@ -0,0 +1,95 @@ +package com.hippo.ehviewer.network; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.UnknownHostException; + +import org.apache.http.conn.ConnectTimeoutException; + +import com.hippo.ehviewer.DiskCache; +import com.hippo.ehviewer.R; +import com.hippo.ehviewer.util.Ui; +import com.hippo.ehviewer.util.Util; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.support.v4.util.LruCache; +import android.util.Log; + +/** + * It is not thread safe + * + * @author Hippo + * + */ +public class HttpHelper { + private static final String TAG = "HttpHelper"; + + private static final String userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.76 Safari/537.36"; + private static final int DEFAULT_TIMEOUT = 5 * 1000; + + private int lastEMsgId = R.string.em_unknown_error; + + /** + * Get last error message id + * @return + */ + public int getLastEMsgId() { + return lastEMsgId; + } + + public Bitmap getImage(String urlStr, String key, + LruCache memoryCache, + DiskCache diskCache, boolean getImage) { + HttpURLConnection conn = null; + Bitmap bitmap = null; + try { + Log.d(TAG, "Get Image " + urlStr); + URL url = new URL(urlStr); + conn = (HttpURLConnection)url.openConnection(); + conn.setRequestProperty("User-Agent", userAgent); + conn.setConnectTimeout(DEFAULT_TIMEOUT); + conn.setReadTimeout(DEFAULT_TIMEOUT); + conn.connect(); + InputStream is = conn.getInputStream(); + + if (diskCache == null) { + if (getImage + && (bitmap = BitmapFactory.decodeStream(is, null, Ui.getBitmapOpt())) != null) { + if (memoryCache != null) + memoryCache.put(key, bitmap); + } + } else { + diskCache.put(key, is); + if (memoryCache != null || getImage) { + Bitmap bmp = (Bitmap)diskCache.get(key, Util.BITMAP); + if (bmp != null) { + if (memoryCache != null) + memoryCache.put(key, bmp); + if (getImage) + bitmap = bmp; + } + } + } + } catch (MalformedURLException e) { + lastEMsgId = R.string.em_url_error; + e.printStackTrace(); + } catch (ConnectTimeoutException e) { + lastEMsgId = R.string.em_timeout; + e.printStackTrace(); + } catch (UnknownHostException e) { + lastEMsgId = R.string.em_no_network_2; + e.printStackTrace(); + } catch (IOException e) { + lastEMsgId = R.string.em_network_error; + e.printStackTrace(); + } finally { + if (conn != null) + conn.disconnect(); + } + return bitmap; + } +} diff --git a/src/com/hippo/ehviewer/util/Ui.java b/src/com/hippo/ehviewer/util/Ui.java index 7787201e7..967edd333 100644 --- a/src/com/hippo/ehviewer/util/Ui.java +++ b/src/com/hippo/ehviewer/util/Ui.java @@ -40,6 +40,9 @@ public class Ui { public static Bitmap BITMAP_START_HALF; public static Bitmap BITMAP_START_EMPTY; + public static Bitmap BITMAP_LAUNCH; + public static Bitmap BITMAP_TOUCH; + private static boolean mInit = false; /** @@ -58,7 +61,7 @@ public class Ui { opt.inPurgeable = true; opt.inInputShareable = true; - /* + BITMAP_DOUJINSHI = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.doujinshi), null, opt); BITMAP_MANGAI = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.manga), null, opt); BITMAP_ARTIST_CG = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.artistcg), null, opt); @@ -74,9 +77,10 @@ public class Ui { BITMAP_START = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.star), null, opt); BITMAP_START_HALF = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.star_half), null, opt); BITMAP_START_EMPTY = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.star_empty), null, opt); - */ - OlImageView.setDefaultImage(BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.ic_launcher)) - , BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.ic_touch), null, opt)); + + BITMAP_LAUNCH = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.ic_launcher), null, opt); + BITMAP_TOUCH = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.ic_touch), null, opt); + OlImageView.setDefaultImage(BITMAP_LAUNCH, BITMAP_TOUCH); } /** diff --git a/src/com/hippo/ehviewer/util/Util.java b/src/com/hippo/ehviewer/util/Util.java index 4da2d1180..9068d8aed 100644 --- a/src/com/hippo/ehviewer/util/Util.java +++ b/src/com/hippo/ehviewer/util/Util.java @@ -58,6 +58,7 @@ public class Util { is.close(); os.flush(); os.close(); + buffer = null; } public static final int BITMAP = 0x0; diff --git a/src/com/hippo/ehviewer/widget/LoadImageView.java b/src/com/hippo/ehviewer/widget/LoadImageView.java new file mode 100644 index 000000000..cd78c557c --- /dev/null +++ b/src/com/hippo/ehviewer/widget/LoadImageView.java @@ -0,0 +1,74 @@ +package com.hippo.ehviewer.widget; + +import com.hippo.ehviewer.ImageLoadManager; +import com.hippo.ehviewer.util.Ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; + +public class LoadImageView extends ImageView { + @SuppressWarnings("unused") + private static final String TAG = "LoadImageView"; + + public static final int NONE = 0x0; + public static final int LOADING = 0x1; + public static final int LOADED = 0x2; + public static final int FAIL = 0x3; + + private int mState = NONE; + + private String mUrl; + private String mKey; + + public LoadImageView(Context context) { + super(context); + } + public LoadImageView(Context context, AttributeSet attrs) { + super(context, attrs); + } + public LoadImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void setLoadInfo(String url, String key) { + mUrl = url; + mKey = key; + } + + public synchronized void setState(int state) { + mState = state; + if (mState != FAIL) + setClickable(false); + } + + public void setOnClickListener(ImageLoadManager ilm) { + setOnClickListener(new OnClickListener(ilm)); + } + + public String getUrl() { + return mUrl; + } + + public String getKey() { + return mKey; + } + + public synchronized int getState() { + return mState; + } + + class OnClickListener implements View.OnClickListener { + private ImageLoadManager mImageLoadManager; + public OnClickListener(ImageLoadManager imageLoadManager) { + mImageLoadManager = imageLoadManager; + } + + @Override + public void onClick(View v) { + LoadImageView.this.setImageBitmap(Ui.BITMAP_LAUNCH); + mImageLoadManager.add(LoadImageView.this, true); + } + } +}