├── 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 clz = (Class) Class 129 | .forName("android.webkit.WebSettingsClassic"); 130 | Class webViewClassicClz = (Class) Class 131 | .forName("android.webkit.WebViewClassic"); 132 | Constructor 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 | 2 | 3 | 8 | 9 | 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 | --------------------------------------------------------------------------------