├── Library
├── .classpath
├── .project
├── .settings
│ └── .gitignore
├── AndroidManifest.xml
├── bin
│ └── .gitignore
├── gen
│ └── .gitignore
├── proguard-project.txt
├── project.properties
├── res
│ └── .gitignore
└── src
│ └── com
│ └── matsuhiro
│ └── android
│ ├── connect
│ └── NetworkUtils.java
│ ├── download
│ ├── DownloadException.java
│ ├── DownloadManager.java
│ ├── DownloadTask.java
│ ├── DownloadTaskListener.java
│ ├── FileAlreadyExistException.java
│ ├── NoMemoryException.java
│ ├── OtherHttpErrorException.java
│ ├── SpecifiedUrlIsNotFoundException.java
│ ├── TaskManageThread.java
│ └── TaskQueue.java
│ └── storage
│ └── StorageUtils.java
├── README.md
└── SampleApp
├── .classpath
├── .project
├── AndroidManifest.xml
├── ic_launcher-web.png
├── libs
└── android-support-v4.jar
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── drawable-xxhdpi
│ └── ic_launcher.png
├── layout
│ └── activity_main.xml
├── menu
│ └── main.xml
├── values-sw600dp
│ └── dimens.xml
├── values-sw720dp-land
│ └── dimens.xml
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
└── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── src
└── com
└── matsuhiro
└── android
└── sample
└── app
├── ImageUrls.java
└── MainActivity.java
/Library/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Library/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidDownloadMangerLib
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Library/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/Library/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Library/bin/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/Library/gen/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/Library/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/Library/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-18
15 | android.library=true
16 |
--------------------------------------------------------------------------------
/Library/res/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/connect/NetworkUtils.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.connect;
3 |
4 | import android.annotation.SuppressLint;
5 | import android.annotation.TargetApi;
6 | import android.content.Context;
7 | import android.net.ConnectivityManager;
8 | import android.net.NetworkInfo;
9 | import android.net.http.HttpResponseCache;
10 | import android.os.Build;
11 | import android.webkit.WebSettings;
12 | import android.webkit.WebView;
13 |
14 | import java.io.File;
15 | import java.io.IOException;
16 | import java.lang.reflect.Constructor;
17 |
18 | public class NetworkUtils {
19 |
20 | public static boolean isNetworkAvailable(Context context) {
21 | ConnectivityManager connectivity = (ConnectivityManager) context
22 | .getSystemService(Context.CONNECTIVITY_SERVICE);
23 | if (connectivity == null) {
24 | return false;
25 | } else {
26 | NetworkInfo[] info = connectivity.getAllNetworkInfo();
27 | if (info != null) {
28 | for (int i = 0; i < info.length; i++) {
29 | if (info[i].getState() == NetworkInfo.State.CONNECTED
30 | || info[i].getState() == NetworkInfo.State.CONNECTING) {
31 | return true;
32 | }
33 | }
34 | }
35 | }
36 | return false;
37 | }
38 |
39 | public static void disableConnectionReuseIfNecessary() {
40 | // HTTP connection reuse which was buggy pre-froyo
41 | if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.FROYO) {
42 | System.setProperty("http.keepAlive", "false");
43 | }
44 | }
45 |
46 | private static File getCacheDir(Context context, boolean internal) {
47 | if (internal) {
48 | return context.getCacheDir();
49 | } else {
50 | return context.getExternalCacheDir();
51 | }
52 | }
53 |
54 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
55 | public static void enableHttpResponseCache(Context context, boolean internal, long size) {
56 | long httpCacheSize;
57 | if (size <= 0) {
58 | httpCacheSize = 10 * 1024 * 1024; // 10 MiB
59 | } else {
60 | httpCacheSize = size;
61 | }
62 | File httpCacheDir = new File(getCacheDir(context, internal), "http");
63 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
64 | try {
65 | android.net.http.HttpResponseCache.install(httpCacheDir, httpCacheSize);
66 | } catch (IOException e) {
67 | }
68 | }
69 | }
70 |
71 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
72 | public static void flushHttpResponseCache() {
73 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
74 | HttpResponseCache cache = HttpResponseCache.getInstalled();
75 | if (cache != null) {
76 | cache.flush();
77 | }
78 | }
79 | }
80 |
81 | private static String mUserAgent;
82 |
83 | public static String getUserAgent(Context context) {
84 | if (mUserAgent instanceof String) {
85 | return mUserAgent;
86 | }
87 | mUserAgent = getDefaultUserAgentString(context);
88 | return mUserAgent;
89 | }
90 |
91 | public static String getDefaultUserAgentString(Context context) {
92 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
93 | String userAgent = NewApiWrapperForUserAgent.getUserAgentJellyBeanMR1(context);
94 | return userAgent;
95 | }
96 |
97 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
98 | String userAgent = NewApiWrapperForUserAgent.getUserAgentJellyBean(context);
99 | return userAgent;
100 | }
101 |
102 | try {
103 | Constructor constructor = WebSettings.class.getDeclaredConstructor(
104 | Context.class, WebView.class);
105 | constructor.setAccessible(true);
106 | try {
107 | WebSettings settings = constructor.newInstance(context, null);
108 | String userAgent = settings.getUserAgentString();
109 | return userAgent;
110 | } finally {
111 | constructor.setAccessible(false);
112 | }
113 | } catch (Exception e) {
114 | String userAgent = new WebView(context).getSettings().getUserAgentString();
115 | return userAgent;
116 | }
117 | }
118 |
119 | @SuppressLint("NewApi")
120 | private static class NewApiWrapperForUserAgent {
121 | static String getUserAgentJellyBeanMR1(Context context) {
122 | return WebSettings.getDefaultUserAgent(context);
123 | }
124 |
125 | static String getUserAgentJellyBean(Context context) {
126 | try {
127 | @SuppressWarnings("unchecked")
128 | Class extends WebSettings> clz = (Class extends WebSettings>) Class
129 | .forName("android.webkit.WebSettingsClassic");
130 | Class> webViewClassicClz = (Class>) Class
131 | .forName("android.webkit.WebViewClassic");
132 | Constructor extends WebSettings> constructor = clz.getDeclaredConstructor(
133 | Context.class, webViewClassicClz);
134 | constructor.setAccessible(true);
135 | try {
136 | WebSettings settings = constructor.newInstance(context, null);
137 | String userAgent = settings.getUserAgentString();
138 | return userAgent;
139 | } finally {
140 | constructor.setAccessible(false);
141 | }
142 | } catch (Exception e) {
143 | String userAgent = new WebView(context).getSettings().getUserAgentString();
144 | return userAgent;
145 | }
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/DownloadException.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.download;
3 |
4 | public class DownloadException extends Exception {
5 | private static final long serialVersionUID = 1L;
6 |
7 | private String mExtra;
8 |
9 | public DownloadException(String message) {
10 | super(message);
11 | }
12 |
13 | public DownloadException(String message, String extra) {
14 | super(message);
15 | mExtra = extra;
16 | }
17 |
18 | public String getExtra() {
19 | return mExtra;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/DownloadManager.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.download;
3 |
4 | import android.content.Context;
5 | import android.os.Handler;
6 | import android.os.HandlerThread;
7 | import android.os.Looper;
8 | import android.os.Message;
9 |
10 | import java.lang.ref.WeakReference;
11 | import java.net.MalformedURLException;
12 | import java.util.TreeMap;
13 | import java.util.concurrent.ConcurrentHashMap;
14 |
15 | public class DownloadManager {
16 | public TreeMap mThreads = new TreeMap();
17 |
18 | private DownloadHandler mDownloadHandler;
19 |
20 | private TaskQueue mTaskQueue;
21 |
22 | private TaskManageThread mTaskManageThread;
23 |
24 | private static final int NUMBER_OF_THREADS_IN_SAME_TIME = 20;
25 |
26 | private static final int ADD_TASK = 0;
27 |
28 | private static final int PAUSE_TASK = 1;
29 |
30 | private static final int RESUME_TASK = 2;
31 |
32 | private static final int DELETE_TASK = 3;
33 |
34 | private ConcurrentHashMap mDownloadTasks;
35 | private ConcurrentHashMap mPausedDownloadTasks;
36 |
37 | private Handler mDownloadListenerHandelr = null;
38 |
39 | public DownloadManager(Context context, Handler handler) {
40 | mDownloadListenerHandelr = handler;
41 | HandlerThread handlerThread = new HandlerThread("DownlaodManagerThread");
42 | handlerThread.start();
43 |
44 | mDownloadTasks = new ConcurrentHashMap();
45 | mPausedDownloadTasks = new ConcurrentHashMap();
46 |
47 | Looper looper = handlerThread.getLooper();
48 | mDownloadHandler = new DownloadHandler(looper, context, this);
49 | mTaskQueue = new TaskQueue(NUMBER_OF_THREADS_IN_SAME_TIME);
50 | mTaskManageThread = new TaskManageThread(mTaskQueue);
51 | mTaskManageThread.start();
52 | }
53 |
54 | private void notifyEvent(final DownloadTask task, final int event, final String url, final Throwable error) {
55 | if (mDownloadListenerHandelr == null) {
56 | return;
57 | }
58 | mDownloadListenerHandelr.post(new Runnable() {
59 | public void run() {
60 | DownloadTaskListener listener = task.getListener();
61 | if (!(listener instanceof DownloadTaskListener)) {
62 | return;
63 | }
64 | switch (event) {
65 | case EVENT_ADDED:
66 | listener.queuedTask(task);
67 | break;
68 | case EVENT_PAUSED:
69 | listener.pausedDownload(task);
70 | break;
71 | case EVENT_RESUMED:
72 | listener.resumedDownload(task);
73 | break;
74 | case EVENT_DELETED:
75 | listener.deletedDownload(task);
76 | break;
77 | case EVENT_ERROR:
78 | listener.errorDownload(task, error);
79 | break;
80 | }
81 | }
82 | });
83 | }
84 |
85 | public static final int EVENT_ADDED = 1;
86 | public static final int EVENT_COMPLETED = EVENT_ADDED + 1;
87 | public static final int EVENT_PAUSED = EVENT_COMPLETED + 1;
88 | public static final int EVENT_RESUMED = EVENT_PAUSED + 1;
89 | public static final int EVENT_DELETED = EVENT_RESUMED + 1;
90 | public static final int EVENT_PROGRESS = EVENT_DELETED + 1;
91 | public static final int EVENT_ERROR = EVENT_PROGRESS + 1;
92 |
93 | public void addTask(DownloadTask task) {
94 | sendMessage(ADD_TASK, 0, 0, task);
95 | }
96 |
97 | public void pause(String url) {
98 | DownloadTask task = mDownloadTasks.get(url);
99 | if (task instanceof DownloadTask) {
100 | sendMessage(PAUSE_TASK, 0, 0, task);
101 | }
102 | }
103 |
104 | public void resume(String url) {
105 | DownloadTask task = mPausedDownloadTasks.get(url);
106 | if (task instanceof DownloadTask) {
107 | sendMessage(RESUME_TASK, 0, 0, task);
108 | }
109 | }
110 |
111 | public void delete(String url) {
112 | DownloadTask task = mDownloadTasks.get(url);
113 | if (task instanceof DownloadTask) {
114 | sendMessage(DELETE_TASK, 0, 0, task);
115 | return;
116 | }
117 | task = mPausedDownloadTasks.get(url);
118 | if (task instanceof DownloadTask) {
119 | sendMessage(DELETE_TASK, 0, 0, task);
120 | }
121 | }
122 |
123 | public void notifyCompleted() {
124 | mTaskQueue.notifyComplete();
125 | }
126 |
127 | private void sendMessage(int what, int arg1, int arg2, Object obj) {
128 | Message msg = new Message();
129 | msg.what = what;
130 | msg.arg1 = arg1;
131 | msg.arg2 = arg2;
132 | msg.obj = obj;
133 | mDownloadHandler.sendMessage(msg);
134 | }
135 |
136 | private static class DownloadHandler extends Handler {
137 | private final WeakReference mConextRef;
138 | private final WeakReference mDownloadManagerRef;
139 |
140 | DownloadHandler(Looper looper, Context context, DownloadManager dnManager) {
141 | super(looper);
142 | mConextRef = new WeakReference(context);
143 | mDownloadManagerRef = new WeakReference(dnManager);
144 | }
145 |
146 | @Override
147 | public void handleMessage(Message msg) {
148 | Context context = mConextRef.get();
149 | if (!(context instanceof Context)) {
150 | // error
151 | return;
152 | }
153 | DownloadManager dnMgr = mDownloadManagerRef.get();
154 | DownloadTask task = (DownloadTask)msg.obj;
155 | switch(msg.what) {
156 | case ADD_TASK:
157 | {
158 | String url = task.getUrl();
159 | if (dnMgr.mDownloadTasks.containsKey(url)) {
160 | DownloadException e = new DownloadException("" + url + " is downloading");
161 | dnMgr.notifyEvent(task, EVENT_ERROR, url, e);
162 | }
163 | if (dnMgr.mPausedDownloadTasks.containsKey(url)) {
164 | DownloadException e = new DownloadException("" + url + " is paused");
165 | dnMgr.notifyEvent(task, EVENT_ERROR, url, e);
166 | }
167 | dnMgr.mDownloadTasks.put(url, task);
168 | dnMgr.mTaskQueue.putTask(task);
169 | dnMgr.notifyEvent(task, EVENT_ADDED, url, null);
170 | }
171 | break;
172 | case PAUSE_TASK:
173 | {
174 | task.cancel();
175 | String url = task.getUrl();
176 | dnMgr.mDownloadTasks.remove(url);
177 | dnMgr.mTaskQueue.removeTask(task);
178 | try {
179 | DownloadTask newTask = new DownloadTask(
180 | task.getContext(),
181 | dnMgr,
182 | task.getUrl(),
183 | task.getFileName(),
184 | task.getPath(),
185 | task.getListener());
186 | dnMgr.mPausedDownloadTasks.put(url, newTask);
187 | dnMgr.notifyEvent(task, EVENT_PAUSED, url, null);
188 | } catch (MalformedURLException e) {
189 | e.printStackTrace();
190 | dnMgr.notifyEvent(task, EVENT_ERROR, url, e);
191 | }
192 | }
193 | break;
194 | case RESUME_TASK:
195 | {
196 | String url = task.getUrl();
197 | dnMgr.mPausedDownloadTasks.remove(url);
198 | dnMgr.mDownloadTasks.put(url, task);
199 | dnMgr.mTaskQueue.putTask(task);
200 | dnMgr.notifyEvent(task, EVENT_RESUMED, url, null);
201 | }
202 | break;
203 | case DELETE_TASK:
204 | {
205 | task.cancel();
206 | String url = task.getUrl();
207 | dnMgr.mPausedDownloadTasks.remove(url);
208 | dnMgr.mDownloadTasks.remove(url);
209 | dnMgr.mTaskQueue.removeTask(task);
210 | dnMgr.notifyEvent(task, EVENT_DELETED, url, null);
211 | }
212 | break;
213 | default:
214 | break;
215 | }
216 | }
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/DownloadTask.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.download;
3 |
4 | import com.matsuhiro.android.connect.NetworkUtils;
5 | import com.matsuhiro.android.storage.StorageUtils;
6 |
7 | import org.apache.http.conn.ConnectTimeoutException;
8 |
9 | import android.accounts.NetworkErrorException;
10 | import android.content.Context;
11 | import android.os.AsyncTask;
12 | import android.text.TextUtils;
13 | import android.util.Log;
14 |
15 | import java.io.BufferedInputStream;
16 | import java.io.File;
17 | import java.io.FileNotFoundException;
18 | import java.io.IOException;
19 | import java.io.InputStream;
20 | import java.io.RandomAccessFile;
21 | import java.net.HttpURLConnection;
22 | import java.net.MalformedURLException;
23 | import java.net.URL;
24 |
25 | public class DownloadTask extends AsyncTask {
26 |
27 | public final static int TIME_OUT = 30000;
28 |
29 | private final static int BUFFER_SIZE = 1024 * 8;
30 |
31 | private static final String TAG = DownloadTask.class.getSimpleName();
32 |
33 | private static final boolean DEBUG = true;
34 |
35 | private static final String TEMP_SUFFIX = ".download";
36 |
37 | private HttpURLConnection mConnection = null;
38 |
39 | private File mFile;
40 |
41 | private File mTempFile;
42 |
43 | private String mUrlString;
44 |
45 | private String mFileName;
46 |
47 | private String mPath;
48 |
49 | private URL mURL;
50 |
51 | private DownloadTaskListener mListener;
52 |
53 | private Context mContext;
54 |
55 | private long mDownloadSize;
56 |
57 | private long mPreviousFileSize;
58 |
59 | private long mTotalSize;
60 |
61 | private long mDownloadPercent;
62 |
63 | private long mNetworkSpeed;
64 |
65 | private long mPreviousTime;
66 |
67 | private long mTotalTime;
68 |
69 | private Throwable mError = null;
70 |
71 | private boolean mInterrupt = false;
72 |
73 | private DownloadManager mDownloadManager;
74 |
75 | private final class ProgressReportingRandomAccessFile extends RandomAccessFile {
76 | private int progress = 0;
77 |
78 | public ProgressReportingRandomAccessFile(File file, String mode)
79 | throws FileNotFoundException {
80 | super(file, mode);
81 | }
82 |
83 | @Override
84 | public void write(byte[] buffer, int offset, int count) throws IOException {
85 | super.write(buffer, offset, count);
86 | progress += count;
87 | mTotalSize = progress;
88 | publishProgress(progress);
89 | }
90 | }
91 |
92 | public DownloadTask(Context context, DownloadManager dnMgr, String url, String path) throws MalformedURLException {
93 | this(context, dnMgr, url, path, null);
94 | }
95 |
96 | public DownloadTask(Context context, DownloadManager dnMgr, String url, String path, DownloadTaskListener listener)
97 | throws MalformedURLException {
98 | this(context, dnMgr, url, null, path, listener);
99 | }
100 |
101 | public DownloadTask(Context context, DownloadManager dnMgr, String url, String name, String path,
102 | DownloadTaskListener listener) throws MalformedURLException {
103 | super();
104 | this.mUrlString = url;
105 | this.mListener = listener;
106 | this.mURL = new URL(url);
107 | if (TextUtils.isEmpty(name)) {
108 | mFileName = new File(mURL.getFile()).getName();
109 | } else {
110 | mFileName = name;
111 | }
112 | this.mFile = new File(path, mFileName);
113 | this.mTempFile = new File(path, mFileName + TEMP_SUFFIX);
114 | this.mContext = context;
115 | mPath = path;
116 | mDownloadManager = dnMgr;
117 | }
118 |
119 | public Context getContext() {
120 | return this.mContext;
121 | }
122 |
123 | public String getUrl() {
124 | return mUrlString;
125 | }
126 |
127 | public String getPath() {
128 | return this.mPath;
129 | }
130 |
131 | public URL getURL() {
132 | return mURL;
133 | }
134 |
135 | public String getFilePath() {
136 | return mFile.getAbsolutePath();
137 | }
138 |
139 | public String getFileName() {
140 | return mFile.getName();
141 | }
142 |
143 | public boolean isInterrupt() {
144 | return mInterrupt;
145 | }
146 |
147 | public long getDownloadPercent() {
148 | return mDownloadPercent;
149 | }
150 |
151 | public long getDownloadSize() {
152 | return mDownloadSize + mPreviousFileSize;
153 | }
154 |
155 | public long getTotalSize() {
156 | return mTotalSize;
157 | }
158 |
159 | public long getDownloadSpeed() {
160 | return this.mNetworkSpeed;
161 | }
162 |
163 | public long getTotalTime() {
164 | return this.mTotalTime;
165 | }
166 |
167 | public DownloadTaskListener getListener() {
168 | return this.mListener;
169 | }
170 |
171 | @Override
172 | protected void onPreExecute() {
173 | mPreviousTime = System.currentTimeMillis();
174 | if (mListener != null)
175 | mListener.preDownload(this);
176 | }
177 |
178 | @Override
179 | protected Long doInBackground(String... params) {
180 |
181 | long id = Thread.currentThread().getId();
182 | mDownloadManager.mThreads.put(id, 1);
183 | long result = -1;
184 | try {
185 | result = download();
186 | } catch (NetworkErrorException e) {
187 | mError = e;
188 | } catch (FileAlreadyExistException e) {
189 | mError = e;
190 | } catch (NoMemoryException e) {
191 | mError = e;
192 | } catch (IOException e) {
193 | mError = e;
194 | } catch (SpecifiedUrlIsNotFoundException e) {
195 | mError = e;
196 | } catch (OtherHttpErrorException e) {
197 | mError = e;
198 | } finally {
199 | if (mConnection != null) {
200 | mConnection.disconnect();
201 | mConnection = null;
202 | }
203 | }
204 |
205 | return result;
206 | }
207 |
208 | @Override
209 | protected void onProgressUpdate(Integer... progress) {
210 |
211 | if (progress.length > 1) {
212 | mTotalSize = progress[1];
213 | if (mTotalSize == -1) {
214 | if (mListener != null) {
215 | mListener.errorDownload(this, mError);
216 | return;
217 | }
218 | }
219 | }
220 | mTotalTime = System.currentTimeMillis() - mPreviousTime;
221 | mDownloadSize = progress[0];
222 | if (mTotalSize == 0) {
223 | mDownloadPercent = -1;
224 | } else {
225 | mDownloadPercent = (mDownloadSize + mPreviousFileSize) * 100 / mTotalSize;
226 | }
227 | mNetworkSpeed = mDownloadSize / mTotalTime;
228 | if (mListener != null)
229 | mListener.updateProcess(this);
230 | }
231 |
232 | @Override
233 | protected void onPostExecute(Long result) {
234 |
235 | if (result == -1 || mInterrupt || mError != null) {
236 | if (DEBUG && mError != null) {
237 | Log.v(TAG, "Download failed." + mError.getMessage() + ", url " + mUrlString);
238 | }
239 | if (mListener != null) {
240 | mListener.errorDownload(this, mError);
241 | }
242 | mDownloadManager.notifyCompleted();
243 | return;
244 | }
245 | // finish download
246 | mTempFile.renameTo(mFile);
247 | if (mListener != null) {
248 | mListener.finishDownload(this);
249 | }
250 | mDownloadManager.notifyCompleted();
251 | }
252 |
253 | @Override
254 | public void onCancelled() {
255 | super.onCancelled();
256 | mInterrupt = true;
257 | }
258 |
259 | private long download() throws NetworkErrorException, IOException,
260 | SpecifiedUrlIsNotFoundException, FileAlreadyExistException, NoMemoryException, OtherHttpErrorException {
261 |
262 | if (DEBUG) {
263 | Log.v(TAG, "totalSize: " + mTotalSize);
264 | }
265 |
266 | /*
267 | * check net work
268 | */
269 | if (!NetworkUtils.isNetworkAvailable(mContext)) {
270 | throw new NetworkErrorException("Network blocked.");
271 | }
272 |
273 | /*
274 | * check file length
275 | */
276 | String userAgent = NetworkUtils.getUserAgent(mContext);
277 | mConnection = (HttpURLConnection) mURL.openConnection();
278 | mConnection.setRequestMethod("GET");
279 | mConnection.setRequestProperty("User-Agent", userAgent);
280 | mConnection.setRequestProperty("Accept-Encoding", "identity");
281 | if (mTempFile.exists()) {
282 | mPreviousFileSize = mTempFile.length();
283 | mConnection.setRequestProperty("Range", "bytes=" + mPreviousFileSize + "-");
284 | }
285 | mConnection.connect();
286 |
287 | int responseCode = mConnection.getResponseCode();
288 | if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
289 | throw new SpecifiedUrlIsNotFoundException("Not found : " + mUrlString);
290 | } else if (responseCode != HttpURLConnection.HTTP_OK
291 | && responseCode != HttpURLConnection.HTTP_PARTIAL) {
292 | String responseCodeString = Integer.toString(responseCode);
293 | throw new OtherHttpErrorException("http error code : " + responseCodeString, responseCodeString);
294 | }
295 |
296 | boolean isRangeDownload = false;
297 | int length = mConnection.getContentLength();
298 | if (responseCode == HttpURLConnection.HTTP_PARTIAL) {
299 | length += mPreviousFileSize;
300 | isRangeDownload = true;
301 | }
302 |
303 | if (mFile.exists() && length == mFile.length()) {
304 | if (DEBUG) {
305 | Log.v(null, "Output file already exists. Skipping download.");
306 | }
307 | throw new FileAlreadyExistException("Output file already exists. Skipping download.");
308 | }
309 |
310 | /*
311 | * check memory
312 | */
313 | long storage = StorageUtils.getAvailableStorage();
314 | if (DEBUG) {
315 | Log.i(null, "storage:" + storage + " totalSize:" + length);
316 | }
317 |
318 | if (length - mPreviousFileSize > storage) {
319 | throw new NoMemoryException("SD card no memory.");
320 | }
321 |
322 | RandomAccessFile outputStream = new ProgressReportingRandomAccessFile(mTempFile, "rw");
323 |
324 | InputStream inputStream = mConnection.getInputStream();
325 |
326 | publishProgress(0, length);
327 |
328 | int bytesCopied = copy(inputStream, outputStream, isRangeDownload);
329 |
330 | if ((mPreviousFileSize + bytesCopied) != mTotalSize && mTotalSize != -1 && !mInterrupt) {
331 | throw new IOException("Download incomplete: " + bytesCopied + " != " + mTotalSize);
332 | }
333 |
334 | if (DEBUG) {
335 | Log.v(TAG, "Download completed successfully.");
336 | }
337 |
338 | return bytesCopied;
339 |
340 | }
341 |
342 | private int copy(InputStream input, RandomAccessFile output, boolean isRangeDownload) throws IOException,
343 | NetworkErrorException {
344 |
345 | if (input == null || output == null) {
346 | return -1;
347 | }
348 |
349 | byte[] buffer = new byte[BUFFER_SIZE];
350 |
351 | BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
352 | if (DEBUG) {
353 | Log.v(TAG, "length " + output.length());
354 | }
355 |
356 | int count = 0, n = 0;
357 | long errorBlockTimePreviousTime = -1, expireTime = 0;
358 |
359 | try {
360 |
361 | if (isRangeDownload) {
362 | output.seek(output.length());
363 | }
364 |
365 | while (!mInterrupt) {
366 | n = in.read(buffer, 0, BUFFER_SIZE);
367 | if (n == -1) {
368 | break;
369 | }
370 | output.write(buffer, 0, n);
371 | count += n;
372 |
373 | /*
374 | * check network
375 | */
376 | if (!NetworkUtils.isNetworkAvailable(mContext)) {
377 | throw new NetworkErrorException("Network blocked.");
378 | }
379 |
380 | if (mNetworkSpeed == 0) {
381 | if (errorBlockTimePreviousTime > 0) {
382 | expireTime = System.currentTimeMillis() - errorBlockTimePreviousTime;
383 | if (expireTime > TIME_OUT) {
384 | throw new ConnectTimeoutException("connection time out.");
385 | }
386 | } else {
387 | errorBlockTimePreviousTime = System.currentTimeMillis();
388 | }
389 | } else {
390 | expireTime = 0;
391 | errorBlockTimePreviousTime = -1;
392 | }
393 | }
394 | } finally {
395 | mConnection.disconnect();
396 | mConnection = null;
397 | output.close();
398 | in.close();
399 | input.close();
400 | }
401 | return count;
402 | }
403 |
404 | public void cancel() {
405 | this.cancel(true);
406 | mInterrupt = true;
407 | }
408 |
409 | }
410 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/DownloadTaskListener.java:
--------------------------------------------------------------------------------
1 | package com.matsuhiro.android.download;
2 |
3 | public interface DownloadTaskListener {
4 |
5 | public void updateProcess(DownloadTask task);
6 |
7 | public void finishDownload(DownloadTask task);
8 |
9 | public void preDownload(DownloadTask task);
10 |
11 | public void queuedTask(DownloadTask task);
12 |
13 | public void pausedDownload(DownloadTask task);
14 |
15 | public void resumedDownload(DownloadTask task);
16 |
17 | public void deletedDownload(DownloadTask task);
18 |
19 | public void errorDownload(DownloadTask task, Throwable error);
20 | }
21 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/FileAlreadyExistException.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.download;
3 |
4 | public class FileAlreadyExistException extends DownloadException {
5 |
6 | private static final long serialVersionUID = 1L;
7 |
8 | public FileAlreadyExistException(String message) {
9 |
10 | super(message);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/NoMemoryException.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.download;
3 |
4 | public class NoMemoryException extends DownloadException {
5 |
6 | private static final long serialVersionUID = 1L;
7 |
8 | public NoMemoryException(String message) {
9 |
10 | super(message);
11 | // TODO Auto-generated constructor stub
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/OtherHttpErrorException.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.download;
3 |
4 | public class OtherHttpErrorException extends DownloadException {
5 |
6 | private static final long serialVersionUID = 1L;
7 |
8 | public OtherHttpErrorException(String message) {
9 | super(message);
10 | }
11 |
12 | public OtherHttpErrorException(String message, String extra) {
13 | super(message, extra);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/SpecifiedUrlIsNotFoundException.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.download;
3 |
4 | public class SpecifiedUrlIsNotFoundException extends DownloadException {
5 |
6 | private static final long serialVersionUID = 1L;
7 |
8 | public SpecifiedUrlIsNotFoundException(String message) {
9 |
10 | super(message);
11 | // TODO Auto-generated constructor stub
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/TaskManageThread.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.download;
3 |
4 | import android.annotation.TargetApi;
5 | import android.os.AsyncTask;
6 | import android.os.Build;
7 | import android.util.Log;
8 |
9 | public class TaskManageThread, Params> extends Thread {
10 | private static final String TAG = TaskManageThread.class.getSimpleName();
11 |
12 | private volatile boolean mFinishRequested = false;
13 |
14 | private TaskManageCallback mTaskManageCallback = null;
15 |
16 | private TaskQueue mTaskQueue;
17 |
18 | public interface TaskManageCallback {
19 | Params[] getInputParameter(T task);
20 | }
21 |
22 | public void setTaskManageCallback(TaskManageCallback callback) {
23 | mTaskManageCallback = callback;
24 | }
25 |
26 | public TaskManageThread(TaskQueue reqTask) {
27 | mTaskQueue = reqTask;
28 | }
29 |
30 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
31 | @Override
32 | public void run() {
33 | try {
34 | while (!mFinishRequested) {
35 | T task = mTaskQueue.getTask();
36 | if (task != null) {
37 | Params[] p = null;
38 | if (mTaskManageCallback != null) {
39 | p = mTaskManageCallback.getInputParameter(task);
40 | }
41 | task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, p);
42 | Log.d(TAG, "task is execute");
43 | }
44 | }
45 | } catch (Exception e) {
46 | } finally {
47 | Log.d(TAG, "task manage thread is finished");
48 | mTaskQueue.removeAll();
49 | }
50 | }
51 |
52 | public void requestFinish() {
53 | mFinishRequested = true;
54 | interrupt();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/download/TaskQueue.java:
--------------------------------------------------------------------------------
1 | package com.matsuhiro.android.download;
2 |
3 | import java.util.concurrent.BlockingQueue;
4 | import java.util.concurrent.LinkedBlockingQueue;
5 |
6 | import android.os.AsyncTask;
7 | import android.util.Log;
8 |
9 | public class TaskQueue> {
10 | private static final String TAG = TaskQueue.class.getSimpleName();
11 |
12 | private final BlockingQueue mQueue = new LinkedBlockingQueue();
13 |
14 | private volatile int mCount = 0;
15 |
16 | private final int MAXIMUM_RUN_TASK_COUNT;
17 |
18 | public TaskQueue(int maximumCount) {
19 | MAXIMUM_RUN_TASK_COUNT = maximumCount;
20 | }
21 |
22 | public T getTask() {
23 | T task = null;
24 | final int runCount;
25 | synchronized (this) {
26 | runCount = mCount - mQueue.size();
27 | }
28 | Log.d(TAG, "get task, mCount : " + mCount);
29 | Log.d(TAG, "get task, runCount : " + runCount);
30 | if (runCount >= MAXIMUM_RUN_TASK_COUNT) {
31 | synchronized (this) {
32 | try {
33 | Log.d(TAG, "get wait");
34 | this.wait();
35 | } catch (InterruptedException e) {
36 | e.printStackTrace();
37 | }
38 | }
39 | } else {
40 | try {
41 | task = mQueue.take();
42 | Log.d(TAG, "taken task");
43 | } catch (InterruptedException e) {
44 | e.printStackTrace();
45 | return null;
46 | }
47 | }
48 | return task;
49 | }
50 |
51 | public synchronized void putTask(T task) {
52 | try {
53 | mQueue.put(task);
54 | mCount += 1;
55 | Log.d(TAG, "put task, mCount : " + mCount);
56 | notifyAll();
57 | } catch (InterruptedException e) {
58 | e.printStackTrace();
59 | }
60 | }
61 |
62 | public synchronized void removeTask(T task) {
63 | if (task == null) {
64 | return;
65 | }
66 | mQueue.remove(task);
67 | mCount -= 1;
68 | if (mCount < 0) {
69 | mCount = 0;
70 | }
71 | Log.d(TAG, "remove task, mCount : " + mCount);
72 | notifyAll();
73 | }
74 |
75 | public synchronized void notifyComplete() {
76 | mCount -= 1;
77 | if (mCount < 0) {
78 | mCount = 0;
79 | }
80 | Log.d(TAG, "completed task, mCount : " + mCount);
81 | notifyAll();
82 | }
83 |
84 | public void removeAll() {
85 | for (T item : mQueue) {
86 | mQueue.remove(item);
87 | }
88 | }
89 |
90 | public int getCount() {
91 | return mCount;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Library/src/com/matsuhiro/android/storage/StorageUtils.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.storage;
3 |
4 | import android.os.Environment;
5 | import android.os.StatFs;
6 |
7 | public class StorageUtils {
8 |
9 | public static long getAvailableStorage() {
10 |
11 | String storageDirectory = null;
12 | storageDirectory = Environment.getExternalStorageDirectory().toString();
13 |
14 | try {
15 | StatFs stat = new StatFs(storageDirectory);
16 | long avaliableSize = ((long) stat.getAvailableBlocks() * (long) stat.getBlockSize());
17 | return avaliableSize;
18 | } catch (RuntimeException ex) {
19 | return 0;
20 | }
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matsuhiro/AndroidDownloadManger/7f05c73a6323ce6397be17cf2a747f1114011307/README.md
--------------------------------------------------------------------------------
/SampleApp/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/SampleApp/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidDownloadManagerApp
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/SampleApp/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/SampleApp/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matsuhiro/AndroidDownloadManger/7f05c73a6323ce6397be17cf2a747f1114011307/SampleApp/ic_launcher-web.png
--------------------------------------------------------------------------------
/SampleApp/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matsuhiro/AndroidDownloadManger/7f05c73a6323ce6397be17cf2a747f1114011307/SampleApp/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/SampleApp/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/SampleApp/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-18
15 | android.library.reference.1=../Library
16 |
--------------------------------------------------------------------------------
/SampleApp/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matsuhiro/AndroidDownloadManger/7f05c73a6323ce6397be17cf2a747f1114011307/SampleApp/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matsuhiro/AndroidDownloadManger/7f05c73a6323ce6397be17cf2a747f1114011307/SampleApp/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matsuhiro/AndroidDownloadManger/7f05c73a6323ce6397be17cf2a747f1114011307/SampleApp/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matsuhiro/AndroidDownloadManger/7f05c73a6323ce6397be17cf2a747f1114011307/SampleApp/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
14 |
15 |
20 |
21 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/SampleApp/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/SampleApp/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SampleApp/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/SampleApp/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SampleApp/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SampleApp/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SampleApp/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AndroidDownloadManagerApp
5 | Settings
6 | Hello world!
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SampleApp/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/SampleApp/src/com/matsuhiro/android/sample/app/ImageUrls.java:
--------------------------------------------------------------------------------
1 | package com.matsuhiro.android.sample.app;
2 |
3 | public class ImageUrls {
4 |
5 | public static final String[] mUrls =
6 | {
7 | "http://www.mcdonaldgardencenter.com/sites/default/files/imagecache/blog_slideshow_full/windy%20leaf-deep-woods-gree_0.jpg",
8 | "http://www.projekt-querdenken.eu/wiki/images/Gree4.JPG",
9 | "http://forum.rebelscum.com/photogallery/data/1787/gree8.jpg",
10 | "http://picopla.net/wp-content/uploads/2011/09/GREE8-1024x678.jpg",
11 | "http://farm2.staticflickr.com/1363/1348309384_bd576e39de_z.jpg",
12 | "http://i.ebayimg.com/t/Sideshow-Militaries-of-Star-Wars-Commander-Gree-12-Action-Figure-NEW-IN-BOX-/00/s/MTU1OFgxNTY2/$T2eC16JHJIkE9qU3iylHBQ(Qbq,P3g~~60_35.JPG",
13 | "http://external.ak.fbcdn.net/safe_image.php?d=AQCcl6PBmi6mnG1Y&url=http%3A%2F%2Fecx.images-amazon.com%2Fimages%2FI%2F41KdXWt9vRL.jpg",
14 | "http://www.hobbygen.com/bmz_cache/4/400ad625a5a8eb422deafcef077208e9.image.300x450.jpg",
15 | "http://img348.imageshack.us/img348/8673/gree12inch6a0dn.jpg",
16 | "http://cdn.c.photoshelter.com/img-get/I0000oduXNR6OLug/s/650/500/tl201012-gree16.jpg",
17 | "http://www.p-ballet.com/p-ballet_blog/gree16.JPG",
18 | "http://locoseanbo2.s3.amazonaws.com/sites/4e5be154f2b7fb0001000005/contents/content_instance/4fd6476e171f800001000206/files/AE7QA_Gree_16.jpg",
19 | "http://cdn.c.photoshelter.com/img-get/I0000vwtLMUEOM9U/s/650/500/tl201012-gree20.jpg",
20 | "http://nonocamushi.up.seesaa.net/image/Jungle20gree20A4_omote0807OL20E381AEE382B3E38394E383BC.jpg",
21 | "http://www.p-ballet.com/p-ballet_blog/gree20.JPG",
22 | "http://www.1-6th.co.uk/Commander%20Gree/slides/gree%2020.jpg",
23 | "http://www.1-6th.co.uk/Commander%20Gree/slides/gree%2024.jpg",
24 | "http://www.almostheavenrealty.com/images_realestate/10417-gree24.jpg",
25 | "http://i.ebayimg.com/t/GREE-24-000-BTU-18-Seer-Ductless-Mini-Split-Heat-Pump-/00/s/NjQ4WDgwMA==/$(KGrHqR,!hgF!ys+5d!sBQ,fRLj3r!~~60_35.JPG",
26 | "http://gigazine.jp/img/2012/06/08/gree-e3-2012/gree24.jpg",
27 | "http://www.almostheavenrealty.com/images_realestate/10417-gree28.jpg",
28 | "http://gigazine.jp/img/2012/06/08/gree-e3-2012/gree28.jpg",
29 | "http://i251.photobucket.com/albums/gg283/tupmeier_2007/bap%20spring%20fling/BramptonAssemblyPlantMeetAndGree-28.jpg",
30 | "http://saiseki-p.jp/img/gree28.jpg",
31 | "http://blockyourid.com/~gbpprorg/judicial-inc/97gree32.jpg",
32 | "http://www.travelmaniac.com/greece/px_gree32.jpg",
33 | "http://nooneread.files.wordpress.com/2012/02/gree32.jpeg?w=500&h=426",
34 | "http://a0.twimg.com/profile_images/2573276533/image.jpg",
35 | "http://i.ebayimg.com/t/GREE-36-000-BTU-16-Seer-Ductless-Mini-Split-Heat-Pump-/00/s/NjQ4WDgwMA==/$(KGrHqNHJEoE+WIkmzO)BQTkE5PShQ~~60_35.JPG",
36 | "http://www.almostheavenrealty.com/images_realestate/10417-gree36.jpg",
37 | "http://images.lowes.com/product/converted/847654/847654000297.jpg",
38 | "http://hub1.10ninety.co.uk/cotswoldlettings/epcs/EPC-GREE40-673.jpg",
39 | "http://www.almostheavenrealty.com/images_realestate/10417-gree40.jpg",
40 | "http://skaino.web.fc2.com/greece/gree44a1.jpg",
41 | "http://www.landmarktravel.com.tr/images/tourPhoto/44/gree44.jpg",
42 | "http://a0.twimg.com/profile_images/1376658815/1.jpg",
43 | "http://image.rakuten.co.jp/eton/cabinet/who-small-leather/whc5571/who-s5571-gree-48-t1.jpg",
44 | "http://image.rakuten.co.jp/eton/cabinet/who-small-leather/whc5571/who-s5571-gree-48-t2.jpg",
45 | "http://www.bearwww.com/pic/50/55/gree480.jpg",
46 | "http://i251.photobucket.com/albums/gg283/tupmeier_2007/bap%20spring%20fling/BramptonAssemblyPlantMeetAndGree-52.jpg",
47 | "http://www.fimosw.com/p/urh5i9sbg9gree52u6wu-8921cad8.jpg",
48 | "http://image.dhgate.com/albu_268320182_00/1.0x0.jpg",
49 | "http://image.dhgate.com/albu_268320181_00/1.0x0.jpg",
50 | "http://cache.virtualtourist.com/10/5543578-Gree56s_Profile_Photo.jpg",
51 | "http://ployonline.com/image/gree56.jpg",
52 | "http://mscharmschic.files.wordpress.com/2011/01/pucci_belt_mod_mint_gree_60s_gogo_scooter_dress_60s_mini_4.jpg?w=490",
53 | "http://ployonline.com/image/gree60.jpg",
54 | "http://www.kemcdod.ru/photo/novosti/greece/gree60.jpg",
55 | "http://t0ak.roblox.com/7cec38ddb4b1c2bfa59e8400154682bd",
56 | "http://www.travelmaniac.com/greece/px_gree64.jpg",
57 | "http://ployonline.com/image/gree64.jpg",
58 | "http://images2.wikia.nocookie.net/__cb20110803192455/clonewarsadventures/images/9/9f/Commander_Gree_64.png",
59 | "http://4.bp.blogspot.com/-qolRXWlVevc/Tfv5RSWkbRI/AAAAAAAAIGo/1lGREE68gRo/s1600/20110616P+Kingman+to+Las+Vegas+075.jpg",
60 | "http://images.betterphoto.com/0021/0407291933231072904_gree-72dpi-churchs.jpg",
61 | "http://st64.storage.gree.jp/album/39/47/24243947/ffe340c8_640.jpg",
62 | "http://st64.storage.gree.jp/album/39/47/24243947/9cfbfab8_640.jpg",
63 | "http://st63.storage.gree.jp/album/88/74/21228874/0b650e39_640.jpg",
64 | "http://img32.imageshack.us/img32/4761/gree76.jpg",
65 | "http://ib.lbp.me/img/al/94bae52285db56605f083838b14306994ef3b90c.png",
66 | "http://media.markethealth.com/bannerServer.php?type=image&ad_id=3779&aid=938811",
67 | "http://img.over-blog.com/300x300/3/89/03/72/Backgrounds-5/gree80.jpg",
68 | "http://st118.storage.gree.jp/album/11/37/45171137/d515cbbc_640.jpg",
69 | "http://a1.mzstatic.com/us/r1000/107/Purple/v4/41/76/ea/4176ea5c-893f-ec3d-72f6-2e6217bb05c2/mzl.ymuhsxin.png",
70 | "http://media.rightmove.co.uk/40k/39887/39887_GREE84_IMG_00_0000_t.jpg",
71 | "http://cdn-ak.b.st-hatena.com/entryimage/61633902-1317653275.jpg",
72 | "http://thumbnail.image.rakuten.co.jp/@0_mall/karafuru/cabinet/stmp/v2-04.jpg?_ex=128x128",
73 | "https://si0.twimg.com/profile_images/2561968079/bkus042gk9f44a4x8v2w_reasonably_small.jpeg",
74 | "http://www.deviantart.com/download/287987747/a_fantasy_portrait_by_gree92-d4rgkrn.jpg",
75 | "http://www.deviantart.com/download/287987412/a_fantasy_portrait_by_gree92-d4rgkic.jpg",
76 | "http://fc02.deviantart.net/fs71/f/2012/061/b/7/profile_picture_by_gree92-d4rghae.jpg",
77 | "http://t1ak.roblox.com/6691b5bb97921716bec1405b5f99cbf7",
78 | "http://www.thefanclub.com/files/c/110000/MUaLf.jpg",
79 | "http://lh5.ggpht.com/yskCHSz-mQUIDXU11lOf-g72K_PsKovSvq5HLl-CSYc3-fCKGstqlQTt75GRee96iHqeYxK23o7nARBPv8Lr=s580",
80 | "http://www.hollywoodmemorabilia.com/files/cache/marilyn-monroe-ballerina-triptych-by-milton-gree_96a052c2b369d27e1b082299a09c23ba.jpg",
81 | "http://lh5.ggpht.com/yskCHSz-mQUIDXU11lOf-g72K_PsKovSvq5HLl-CSYc3-fCKGstqlQTt75GRee96iHqeYxK23o7nARBPv8Lr=s100-c",
82 | "http://images3.wikia.nocookie.net/__cb57525/halo/images/4/42/MCwithmoreSMGs.jpg",
83 | "http://cdn6.staztic.com/cdn/screenshot/for-gree-100-1.jpg",
84 | "http://cdn5.staztic.com/cdn/screenshot/for-gree-100-3.jpg",
85 | "http://cdn6.staztic.com/cdn/screenshot/ex-for-gree-100-3.jpg",
86 | "http://japan.cnet.com/storage/2011/12/06/4d31d72d4196aefbbfedf47b704ffd68/111206_gree_104.jpg",
87 | "http://xf9.xanga.com/082d60e147030133242554/m97371627.jpg",
88 | "http://x06.xanga.com/aa1d8a0102233141723936/m104572857.bmp",
89 | "http://x34.xanga.com/e76d870172133141723909/m104572833.bmp",
90 | "https://images.thefoundary.com/mgen/child:GREE108-1.jpg?is=500,500,0xffffff&v=20120517100802",
91 | "http://www.mixcd24.jp/data/mixcd24/product/gree108.jpg",
92 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree108(w110).gif",
93 | "http://www.fishingmonthly.com.au/app/webroot/img/uploads/a7446a49f71fed26775e3bda023ac4db_Gree112_4.jpg",
94 | "http://www.fishingmonthly.com.au/app/webroot/img/uploads/a7446a49f71fed26775e3bda023ac4db_Gree112_2.jpg",
95 | "https://www.mypacificpearls.com/shop/images/uploads/round_green_mother_of_pearl_cufflinks.jpg",
96 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/11/15/gree112.jpg",
97 | "https://images.thefoundary.com/mgen/child:GREE116-1.jpg?is=1562,1600,0xffffff&v=20120814161557",
98 | "http://wps.ablongman.com/wps/media/objects/18/19102/illustrations/GREE116.GIF",
99 | "http://farm3.staticflickr.com/2623/3911918395_1d35b1c78b_z.jpg",
100 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/11/16/gree116.jpg",
101 | "https://images.thefoundary.com/mgen/child:GREE120-1.jpg?is=1600,1600,0xffffff&v=20120814161557",
102 | "http://farm3.staticflickr.com/2592/3912705308_893f8d919d_z.jpg",
103 | "http://st63.storage.gree.jp/album/88/74/21228874/dd39b5e7_640.jpg",
104 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/11/18/gree124.jpg",
105 | "http://farm3.staticflickr.com/2657/3911927013_a6439e5c87_z.jpg",
106 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree124.gif",
107 | "http://images.travelnow.com/hotelimages/s/024000/024725A.jpg",
108 | "http://farm3.staticflickr.com/2674/3912716812_d750c82601_z.jpg",
109 | "https://images.thefoundary.com/mgen/child:GREE128-1.jpg?is=203,203,0xffffff&v=20120814161557",
110 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/11/19/gree128.jpg",
111 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/11/20/gree132.jpg",
112 | "http://farm3.staticflickr.com/2571/3911939783_1766939158_z.jpg",
113 | "http://cdn100.iofferphoto.com/img3/item/520/508/753/l_storage-boxe-desing-tin-recycle-battery-save-earth-gree-132d.jpg",
114 | "http://www.boston.goarch.org/assets/images/NewsPhotos/GREE%20132(1).jpg",
115 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/11/21/gree136.jpg",
116 | "http://farm4.staticflickr.com/3429/3911943291_423afda308_z.jpg",
117 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree136.gif",
118 | "http://skaino.web.fc2.com/greece/gree136b1.jpg",
119 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/11/22/gree140.jpg",
120 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree140.gif",
121 | "http://farm3.staticflickr.com/2615/3911947375_154248e74c_z.jpg",
122 | "http://static.priyo.com/files/image/2011/09/12/20110912-Gree-140.jpg",
123 | "http://wps.ablongman.com/wps/media/objects/18/19102/illustrations/GREE144.GIF",
124 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/11/26/gree144.jpg",
125 | "http://farm4.staticflickr.com/3524/3911951549_d79eebb2d3_z.jpg",
126 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree144.gif",
127 | "http://farm3.staticflickr.com/2596/3912739636_f32e5dec00_z.jpg",
128 | "http://m-39b001d84d83a400-m.cocolog-nifty.com/photos/uncategorized/2007/12/02/gree148.jpg",
129 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree148.gif",
130 | "http://gerookteknoflook.nl/IMAGES/TAB_GREE148_B.jpg",
131 | "http://farm3.staticflickr.com/2610/3912743404_ab9819d2fb_z.jpg",
132 | "http://l.yimg.com/ea/img/-/090610/tgyh-s4-ep-6---cast-in-gree-152ujde.jpg?x=400&q=80&n=1&sig=yQjMIkVz96iljqH0Bp0zaQ--",
133 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree152.gif",
134 | "http://farm4.staticflickr.com/3533/3911962925_f4fff999b7_z.jpg",
135 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree156.gif",
136 | "http://www.janis-cd.com/review/images/nyman_gree_156_picture.jpg",
137 | "http://farm3.staticflickr.com/2517/3912746106_b001ec7aea_s.jpg",
138 | "http://www.pocketgamer.co.uk/images/PGuk_spons_gree_160x160.jpg",
139 | "http://static.bitcash.jp/www/feature/spring2012/games/gree_160.gif",
140 | "http://widgets.markosweb.com/w/big/new/g/r/e/gree160.com.gif",
141 | "http://farm4.staticflickr.com/3422/3912755620_296908c8ab_z.jpg",
142 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree164.gif",
143 | "http://tour.dvdworld.ru/Tripstory/Greece/Gree_164.jpg",
144 | "http://iiyokoko.com/gree/gree168.jpg",
145 | "http://farm3.staticflickr.com/2440/3911975443_65b963427a_z.jpg",
146 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree168.gif",
147 | "http://lens-eye.cocolog-nifty.com/photos/uncategorized/2009/09/17/gree168.jpg",
148 | "http://farm3.staticflickr.com/2491/3911979471_8fb461641f_z.jpg",
149 | "http://iiyokoko.com/gree/gree172.jpg",
150 | "http://lens-eye.cocolog-nifty.com/blog/images/gree172.jpg",
151 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree172.gif",
152 | "http://farm3.staticflickr.com/2495/3912767472_ea9409cfe1_z.jpg",
153 | "http://www.jidousyamenkyo.jp/gakkou/img/gree/gree_176.gif",
154 | "http://lens-eye.cocolog-nifty.com/blog/images/gree176.jpg",
155 | "http://www.pittjug.org/catalog/pics/17___19__LCD_Monitor_TV.jpg",
156 | "http://farm3.staticflickr.com/2618/3912771318_b817a5b045_z.jpg",
157 | "http://www.artfixdaily.com/images/cache/Gerald-McBoingBoing-In-Parlor-on-Scooter-gree180x146.jpg?1336600833",
158 | "http://4.bp.blogspot.com/-BqYYngE5N6U/Te0CEgfK-eI/AAAAAAAAAOM/QqhL45KBi5U/s320/2011-06-06%2B09.21.31.jpg",
159 | "http://graphics8.nytimes.com/images/2004/10/03/arts/gree.184.1.jpg",
160 | "http://graphics8.nytimes.com/images/2004/10/26/business/27cnd-gree.184.jpg",
161 | "http://japan.cnet.com/storage/2012/05/08/922b78800dab0b7f1f14168cef2a9375/120508_gree184x138.jpg",
162 | "http://www.geus.dk/publications/bull-gl/gree-188.jpg",
163 | "http://iiyokoko.com/gree/gree188.jpg",
164 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree188.gif",
165 | "http://skaino.web.fc2.com/greece/gree188a1.jpg",
166 | "http://blog.jat.or.jp/talent/wp-content/uploads/2012/10/GREE-192x300.jpg",
167 | "http://iiyokoko.com/gree/gree192.jpg",
168 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree192.gif",
169 | "http://skaino.web.fc2.com/greece/gree192a1.jpg",
170 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree196.gif",
171 | "http://www.maminuklubs.lv/content/images_cache/mk_news_1341999441_gree_196_200_0.jpg",
172 | "http://www.barker-inc.com/images/PropImages/gree200b_01.jpg",
173 | "http://www.fatquartershop.com/store/stores_app/images/images_499/Chicopee-PWDS030-GREE-200.jpg",
174 | "http://www.fatquartershop.com/store/stores_app/images/images_499/Chicopee-PWDS033-GREE-200.jpg",
175 | "http://img0037.popscreencdn.com/113316286_amazoncom-biotec-foods---bio-gestin-gree-200-caplets-.jpg",
176 | "http://2.bp.blogspot.com/_PpNuf6LljjQ/TPfGFv_jN6I/AAAAAAAAFi4/OCYTuNsy3xE/s1600/gree204.jpg",
177 | "http://picopla.net/wp-content/uploads/2011/12/GREE-204x300.png",
178 | "http://iiyokoko.com/gree/gree204.jpg",
179 | "http://blog.jat.or.jp/talent/wp-content/uploads/2012/09/GREE-204x150.jpg",
180 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree208.gif",
181 | "http://iiyokoko.com/gree/gree208.jpg",
182 | "http://clubct.org/HighSchool/Riffrunner.gif",
183 | "http://replacemyair.com/images/1310532304623-1243620059.bmp",
184 | "http://ag-transition.org/wp-content/uploads/2012/05/gree-212x300.jpg",
185 | "http://www.fishingmonthly.com.au/app/webroot/img/uploads/a3831880ebf4e89c86e4c05a33b2da78_Gree212_2.jpg",
186 | "http://www.fishingmonthly.com.au/app/webroot/img/uploads/a3831880ebf4e89c86e4c05a33b2da78_Gree212_3.jpg",
187 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree216.gif",
188 | "http://iiyokoko.com/gree/gree216.jpg",
189 | "http://a0.twimg.com/profile_images/1337397895/constanta.jpg",
190 | "http://www.victoria.ac.nz/images/staffpics/judy-deuling.jpg",
191 | "http://iiyokoko.com/gree/gree220.jpg",
192 | "http://images04.olx.com.br/ui/18/51/49/1330443662_323884249_1-Fotos-de--Ar-condicionados-Gree-220-volts-110-volts.jpg",
193 | "http://4.bp.blogspot.com/_umHvYUqP_HA/S_KJU238GWI/AAAAAAAADTw/GplxEGxKf3o/s640/P1010008.JPG",
194 | "http://techdiem.com/wp-content/plugins/rss-poster/cache/c8878_gree-220x146.jpg",
195 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree224.gif",
196 | "http://www.jidousyamenkyo.jp/gakkou/img/gree/gree_224.gif",
197 | "http://iiyokoko.com/gree/gree224.jpg",
198 | "http://lens-eye.cocolog-nifty.com/photos/uncategorized/2009/09/14/gree228.jpg",
199 | "http://t3ak.roblox.com/249a621c482303e636d8570e40692556",
200 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree232.gif",
201 | "http://skaino.web.fc2.com/greece/gree232.jpg",
202 | "http://www.criacaosites.com/wp-content/uploads/2012/09/jogos-do-gree-232x300.jpg",
203 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree232(w110).gif",
204 | "http://www.myfsn.com/images/flowerdatabase/festive-photo-box-fresh-arrangemetn-of-winter-gree.236.jpg",
205 | "http://iiyokoko.com/gree/gree236.jpg",
206 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree236.gif",
207 | "http://www.wsws.org/images/2012apr/a20-gree-240.jpg",
208 | "http://img.hisupplier.com/var/userImages/2011-06/17/110055639_SANHE_DJF_C_series_cone_ventilation_fan_horn_cone_fan_for_poultry_house_and_gree_240.jpg",
209 | "http://www.sneakersdiscountprice.com/images/fileimg058/Supra%20Skytop%20For%20Men%20Shoes%20Grey%20Gree%20244.jpg",
210 | "http://iiyokoko.com/gree/gree244.jpg",
211 | "http://www.sport.gr/files/news/2010-09-25/resized/1285456858_gree_244_340.jpg",
212 | "http://minecraftpvp.com/images/player/gree248?size=16",
213 | "http://ascii.jp/elem/000/000/109/109972/panya_gree_248x.jpg",
214 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree248.gif",
215 | "http://iiyokoko.com/gree/gree248.jpg",
216 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree252.gif",
217 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree252(w110).gif",
218 | "http://api.vwheritage.com/_img/small/52638761_01_small.jpg",
219 | "http://www.flagsoftheworldshop.co.uk/images/medium/Greenland_MED.gif",
220 | "http://iiyokoko.com/gree/gree256.jpg",
221 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree260.gif",
222 | "http://iiyokoko.com/gree/gree260.jpg",
223 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree260(w110).gif",
224 | "http://farm3.staticflickr.com/2240/1990616939_52338a85c6_z.jpg",
225 | "http://farm3.staticflickr.com/2058/1990674035_d6c089687a_z.jpg",
226 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree264.gif",
227 | "http://farm3.staticflickr.com/2118/1990683209_c095c7f129_z.jpg",
228 | "http://iiyokoko.com/gree/gree268.jpg",
229 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree268.gif",
230 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree268(w110).gif",
231 | "http://joshi-ma.net/blog/image/20100705_a01.jpg",
232 | "http://iiyokoko.com/gree/gree272.jpg",
233 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree272.gif",
234 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree272(w110).gif",
235 | "http://www.nzetc.org/etexts/SatGree/SatGree272(t100).gif",
236 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree276.gif",
237 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree280.gif",
238 | "http://media2.intoday.in/conclave/conclave/images/video/germaine-gree280_032811054554.jpg",
239 | "http://images.vg247.com/current//2012/06/gree-280x80.jpg",
240 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree256.gif",
241 | "http://mimg.ugo.com/200807/27091/cuts/mighty-muggs-gree_288x288.jpg",
242 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree288.gif",
243 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree288(w110).gif",
244 | "http://content1.myyearbook.com/thumb_userimages/square/2011/07/26/05/thm_phpcyIfgA_0_0_400_400.jpg",
245 | "http://www.clemson.edu/cafls/news_research/images/energy_conserving_gree_292px.jpg",
246 | "http://www.swinburne.edu.au/design/gallery/images/2007_2_KyeGree_292_1.jpg",
247 | "http://cdn.c.photoshelter.com/img-get/I0000TRP3BKzGU50/s/750/750/GREE-292.jpg",
248 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree292.gif",
249 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree284.gif",
250 | "http://www.jidousyamenkyo.jp/gakkou/img/gree/gree_284.gif",
251 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree284(w110).gif",
252 | "http://www.nzetc.org/etexts/SatGree/SatGree284(t100).gif",
253 | "http://unsolublesugar.com/wp/wp-content/uploads/2012/09/GREE-300x300.jpg",
254 | "http://www.akomplice-clothing.com/store/images/evobox/Evolve-Box-logo-GREE300.jpg",
255 | "http://friskymongoose.com/wp-content/uploads/2012/09/zombie_icon_gree-300x300.png",
256 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree304.gif",
257 | "http://nzetc.victoria.ac.nz/etexts/WH2Gree/WH2Gree304a.jpg",
258 | "http://c1933542.cdn.cloudfiles.rackspacecloud.com/childbooks/thumbnails/search/Gree304.gif",
259 | "http://nzetc.victoria.ac.nz/etexts/SatGree/SatGree308.gif",
260 | "http://photos1.zillow.com/p_d/ISmm8tpz86ynqb.jpg",
261 | "http://osampokit3.sakura.ne.jp/osampo_premium/12pics/20120505-1.jpg"};
262 | }
263 |
--------------------------------------------------------------------------------
/SampleApp/src/com/matsuhiro/android/sample/app/MainActivity.java:
--------------------------------------------------------------------------------
1 |
2 | package com.matsuhiro.android.sample.app;
3 |
4 | import com.matsuhiro.android.download.DownloadManager;
5 | import com.matsuhiro.android.download.DownloadTask;
6 | import com.matsuhiro.android.download.DownloadTaskListener;
7 |
8 | import android.os.AsyncTask;
9 | import android.os.Bundle;
10 | import android.os.Environment;
11 | import android.os.Handler;
12 | import android.app.Activity;
13 | import android.app.AlertDialog;
14 | import android.util.Log;
15 | import android.view.Menu;
16 | import android.widget.TextView;
17 |
18 | import java.net.MalformedURLException;
19 |
20 | public class MainActivity extends Activity {
21 |
22 | private int mTotalCount;
23 | private String mPath;
24 | private int mErrorNum;
25 | private int mSuccessNum;
26 | private int mQueuedNum;
27 | private DownloadManager mMgr;
28 |
29 | private TextView mText;
30 | private TextView mErrorText;
31 | private long mStartTime;
32 | private String mErrorUrls = "";
33 |
34 | private void updateText() {
35 | String text = "success : " + mSuccessNum + "/ error : " + mErrorNum + " / queued : " + mQueuedNum;
36 | mText.setText(text);
37 | }
38 |
39 | @Override
40 | protected void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | setContentView(R.layout.activity_main);
43 | mText = (TextView)findViewById(R.id.text_field);
44 | mErrorText = (TextView)findViewById(R.id.error_url);
45 |
46 | mErrorNum = 0;
47 | mSuccessNum = 0;
48 | mQueuedNum = 0;
49 | mTotalCount = ImageUrls.mUrls.length;
50 | updateText();
51 | mPath = this.getExternalFilesDir(null).getAbsolutePath();
52 |
53 | mMgr = new DownloadManager(this, new Handler());
54 |
55 | mStartTime = System.currentTimeMillis();
56 | android.os.Debug.startMethodTracing("dnMgr50");
57 | for (int i = 0; i < mTotalCount; i++) {
58 | try {
59 | DownloadTask task = new DownloadTask(this, mMgr, ImageUrls.mUrls[i], mPath, mDownloadTaskListener);
60 | mQueuedNum++;
61 | mMgr.addTask(task);
62 | } catch (MalformedURLException e) {
63 | e.printStackTrace();
64 | }
65 | }
66 |
67 | }
68 |
69 | DownloadTaskListener mDownloadTaskListener = new DownloadTaskListener() {
70 |
71 | @Override
72 | public void updateProcess(DownloadTask task) {
73 | // TODO Auto-generated method stub
74 |
75 | }
76 |
77 | @Override
78 | public void finishDownload(DownloadTask task) {
79 | mSuccessNum++;
80 | updateText();
81 | if ((mSuccessNum + mErrorNum) == mQueuedNum) {
82 | android.os.Debug.stopMethodTracing();
83 | long endTime = System.currentTimeMillis();
84 | long time = endTime - mStartTime;
85 | Log.d("DownloadTest", "time : " + time);
86 | int threadNum = mMgr.mThreads.keySet().size();
87 | new AlertDialog.Builder(MainActivity.this)
88 | .setMessage("" + time + " msec, threadnum " +threadNum)
89 | .show();
90 | }
91 | }
92 |
93 | @Override
94 | public void preDownload(DownloadTask task) {
95 | // TODO Auto-generated method stub
96 |
97 | }
98 |
99 | @Override
100 | public void queuedTask(DownloadTask task) {
101 | // TODO Auto-generated method stub
102 |
103 | }
104 |
105 | @Override
106 | public void pausedDownload(DownloadTask task) {
107 | // TODO Auto-generated method stub
108 |
109 | }
110 |
111 | @Override
112 | public void resumedDownload(DownloadTask task) {
113 | // TODO Auto-generated method stub
114 |
115 | }
116 |
117 | @Override
118 | public void deletedDownload(DownloadTask task) {
119 | // TODO Auto-generated method stub
120 |
121 | }
122 |
123 | @Override
124 | public void errorDownload(DownloadTask task, Throwable error) {
125 | mErrorNum++;
126 | updateText();
127 | mErrorUrls += "\n";
128 | mErrorUrls += task.getUrl();
129 | mErrorText.setText(mErrorUrls);
130 | }
131 |
132 | };
133 |
134 | @Override
135 | public boolean onCreateOptionsMenu(Menu menu) {
136 | // Inflate the menu; this adds items to the action bar if it is present.
137 | getMenuInflater().inflate(R.menu.main, menu);
138 | return true;
139 | }
140 |
141 | }
142 |
--------------------------------------------------------------------------------