35 import org.hedgewars.hedgeroid.Downloader.DownloadService.DownloadTask; |
35 import org.hedgewars.hedgeroid.Downloader.DownloadService.DownloadTask; |
36 |
36 |
37 import android.os.AsyncTask; |
37 import android.os.AsyncTask; |
38 /** |
38 /** |
39 * This is an AsyncTask which will download a zip from an URL and unzip it to a specified path |
39 * This is an AsyncTask which will download a zip from an URL and unzip it to a specified path |
40 * |
40 * |
41 * a typical call to start the task would be new DownloadAsyncTask().execute(getExternalStorage(), "www.hedgewars.org/data.zip"); |
41 * a typical call to start the task would be new DownloadAsyncTask().execute(getExternalStorage(), "www.hedgewars.org/data.zip"); |
42 * @author Xeli |
42 * @author Xeli |
43 * |
43 * |
44 */ |
44 */ |
45 public class DownloadAsyncTask extends AsyncTask<DownloadPackage, Object, Integer> { |
45 public class DownloadAsyncTask extends AsyncTask<DownloadPackage, Object, Integer> { |
46 |
46 |
47 //private final static String URL_WITHOUT_SUFFIX = "http://www.xelification.com/tmp/firebutton."; |
47 //private final static String URL_WITHOUT_SUFFIX = "http://www.xelification.com/tmp/firebutton."; |
48 private final static String URL_ZIP_SUFFIX = ".zip"; |
48 private final static String URL_ZIP_SUFFIX = ".zip"; |
49 private final static String URL_HASH_SUFFIX = ".hash"; |
49 private final static String URL_HASH_SUFFIX = ".hash"; |
50 |
50 |
51 public static final int EXIT_SUCCESS = 0; |
51 public static final int EXIT_SUCCESS = 0; |
52 public static final int EXIT_URLFAIL = 1; |
52 public static final int EXIT_URLFAIL = 1; |
53 public static final int EXIT_CONNERROR = 2; |
53 public static final int EXIT_CONNERROR = 2; |
54 public static final int EXIT_FNF = 3; |
54 public static final int EXIT_FNF = 3; |
55 public static final int EXIT_MD5 = 4; |
55 public static final int EXIT_MD5 = 4; |
56 public static final int EXIT_CANCELLED = 5; |
56 public static final int EXIT_CANCELLED = 5; |
57 |
57 |
58 private DownloadTask task; |
58 private DownloadTask task; |
59 private long lastUpdateMillis = 0; |
59 private long lastUpdateMillis = 0; |
60 |
60 |
61 public DownloadAsyncTask(DownloadTask _task){ |
61 public DownloadAsyncTask(DownloadTask _task){ |
62 task = _task; |
62 task = _task; |
63 } |
63 } |
64 |
64 |
65 /** |
65 /** |
66 * |
66 * |
67 * @param params - A {@link}DownloadTask which gives information about where to download from and store the files to |
67 * @param params - A {@link}DownloadTask which gives information about where to download from and store the files to |
68 */ |
68 */ |
69 protected Integer doInBackground(DownloadPackage...packages) { |
69 protected Integer doInBackground(DownloadPackage...packages) { |
70 DownloadPackage pack = packages[0];//just use one task per execute call for now |
70 DownloadPackage pack = packages[0];//just use one task per execute call for now |
71 |
71 |
72 HttpURLConnection conn = null; |
72 HttpURLConnection conn = null; |
73 MessageDigest digester = null; |
73 MessageDigest digester = null; |
74 String rootZipDest = pack.getPathToStore(); |
74 String rootZipDest = pack.getPathToStore(); |
75 |
75 |
76 File rootDest = new File(rootZipDest);//TODO check for nullpointer, it hints to the absence of an sdcard |
76 File rootDest = new File(rootZipDest);//TODO check for nullpointer, it hints to the absence of an sdcard |
77 rootDest.mkdirs(); |
77 rootDest.mkdirs(); |
78 |
78 |
79 try { |
79 try { |
80 URL url = new URL(pack.getURL() + URL_ZIP_SUFFIX); |
80 URL url = new URL(pack.getURL() + URL_ZIP_SUFFIX); |
81 conn = (HttpURLConnection)url.openConnection(); |
81 conn = (HttpURLConnection)url.openConnection(); |
82 } catch (IOException e) { |
82 } catch (IOException e) { |
83 e.printStackTrace(); |
83 e.printStackTrace(); |
84 return EXIT_URLFAIL; |
84 return EXIT_URLFAIL; |
85 } |
85 } |
86 |
86 |
87 String contentType = conn.getContentType(); |
87 String contentType = conn.getContentType(); |
88 |
88 |
89 if(contentType == null || contentType.contains("zip")){ //Seeing as we provide the url if the contentType is unknown lets assume zips |
89 if(contentType == null || contentType.contains("zip")){ //Seeing as we provide the url if the contentType is unknown lets assume zips |
90 int bytesDecompressed = 0; |
90 int bytesDecompressed = 0; |
91 ZipEntry entry = null; |
91 ZipEntry entry = null; |
92 ZipInputStream input = null; |
92 ZipInputStream input = null; |
93 FileOutputStream output = null; |
93 FileOutputStream output = null; |
94 int kbytesToProcess = conn.getContentLength()/1024; |
94 int kbytesToProcess = conn.getContentLength()/1024; |
95 |
95 |
96 byte[] buffer = new byte[1024]; |
96 byte[] buffer = new byte[1024]; |
97 task.start(kbytesToProcess); |
97 task.start(kbytesToProcess); |
98 |
98 |
99 try { |
99 try { |
100 digester = MessageDigest.getInstance("MD5"); |
100 digester = MessageDigest.getInstance("MD5"); |
101 |
101 |
102 } catch (NoSuchAlgorithmException e1) { |
102 } catch (NoSuchAlgorithmException e1) { |
103 e1.printStackTrace(); |
103 e1.printStackTrace(); |
104 } |
104 } |
105 |
105 |
106 try{ |
106 try{ |
107 input = new ZipInputStream(conn.getInputStream()); |
107 input = new ZipInputStream(conn.getInputStream()); |
108 entry = input.getNextEntry(); |
108 entry = input.getNextEntry(); |
109 }catch(IOException e){ |
109 }catch(IOException e){ |
110 e.printStackTrace(); |
110 e.printStackTrace(); |
111 conn.disconnect(); |
111 conn.disconnect(); |
112 return EXIT_CONNERROR; |
112 return EXIT_CONNERROR; |
113 } |
113 } |
114 |
114 |
115 |
115 |
116 |
116 |
117 while(entry != null){ |
117 while(entry != null){ |
118 |
118 |
119 if(isCancelled()) break; |
119 if(isCancelled()) break; |
120 |
120 |
121 try { |
121 try { |
122 String fileName = entry.getName(); |
122 String fileName = entry.getName(); |
123 File f = new File(rootZipDest + fileName); |
123 File f = new File(rootZipDest + fileName); |
124 bytesDecompressed += entry.getCompressedSize(); |
124 bytesDecompressed += entry.getCompressedSize(); |
125 |
125 |
126 if(entry.isDirectory()){ |
126 if(entry.isDirectory()){ |
127 f.mkdir(); |
127 f.mkdir(); |
128 }else{ |
128 }else{ |
129 if(f.exists()){ |
129 if(f.exists()){ |
130 f.delete(); |
130 f.delete(); |
131 } |
131 } |
132 f.createNewFile(); |
132 f.createNewFile(); |
133 output = new FileOutputStream(f); |
133 output = new FileOutputStream(f); |
134 |
134 |
135 int count = 0; |
135 int count = 0; |
136 while((count = input.read(buffer)) != -1){ |
136 while((count = input.read(buffer)) != -1){ |
137 output.write(buffer, 0, count); |
137 output.write(buffer, 0, count); |
138 digester.update(buffer, 0, count); |
138 digester.update(buffer, 0, count); |
139 if(System.currentTimeMillis() - lastUpdateMillis > 1000){ |
139 if(System.currentTimeMillis() - lastUpdateMillis > 1000){ |
140 lastUpdateMillis = System.currentTimeMillis(); |
140 lastUpdateMillis = System.currentTimeMillis(); |
141 publishProgress(bytesDecompressed, kbytesToProcess, fileName); |
141 publishProgress(bytesDecompressed, kbytesToProcess, fileName); |
142 } |
142 } |
143 } |
143 } |
144 output.flush(); |
144 output.flush(); |
145 input.closeEntry(); |
145 input.closeEntry(); |
146 }//if isDir |
146 }//if isDir |
147 entry = input.getNextEntry(); |
147 entry = input.getNextEntry(); |
148 } catch (FileNotFoundException e) { |
148 } catch (FileNotFoundException e) { |
149 e.printStackTrace(); |
149 e.printStackTrace(); |
150 if(conn != null) conn.disconnect(); |
150 if(conn != null) conn.disconnect(); |
151 return EXIT_FNF; |
151 return EXIT_FNF; |
152 } catch (IOException e) { |
152 } catch (IOException e) { |
153 e.printStackTrace(); |
153 e.printStackTrace(); |
154 if(conn != null) conn.disconnect(); |
154 if(conn != null) conn.disconnect(); |
155 return EXIT_CONNERROR; |
155 return EXIT_CONNERROR; |
156 }finally{ |
156 }finally{ |
157 try { |
157 try { |
158 if( output != null) output.close(); |
158 if( output != null) output.close(); |
159 |
159 |
160 } catch (IOException e) {} |
160 } catch (IOException e) {} |
161 } |
161 } |
162 }//end while(entry != null) |
162 }//end while(entry != null) |
163 if( input != null) |
163 if( input != null) |
164 try { |
164 try { |
165 input.close(); |
165 input.close(); |
166 } catch (IOException e) {} |
166 } catch (IOException e) {} |
167 }else{//end if contentType == "zip" |
167 }else{//end if contentType == "zip" |
168 return EXIT_URLFAIL; |
168 return EXIT_URLFAIL; |
169 } |
169 } |
170 if(conn != null) conn.disconnect(); |
170 if(conn != null) conn.disconnect(); |
171 |
171 |
172 if(checkMD5(digester, pack))return EXIT_SUCCESS; |
172 if(checkMD5(digester, pack))return EXIT_SUCCESS; |
173 else return EXIT_MD5; |
173 else return EXIT_MD5; |
174 } |
174 } |
175 |
175 |
176 //TODO proper result handling |
176 //TODO proper result handling |
177 protected void onPostExecute(Integer result){ |
177 protected void onPostExecute(Integer result){ |
178 task.done(result); |
178 task.done(result); |
179 } |
179 } |
180 |
180 |
181 protected void onProgressUpdate(Object...objects){ |
181 protected void onProgressUpdate(Object...objects){ |
182 task.update((Integer)objects[0], (Integer)objects[1], (String)objects[2]); |
182 task.update((Integer)objects[0], (Integer)objects[1], (String)objects[2]); |
183 } |
183 } |
184 |
184 |
185 protected void onCancelled(){ |
185 protected void onCancelled(){ |
186 onPostExecute(EXIT_CANCELLED); |
186 onPostExecute(EXIT_CANCELLED); |
187 } |
187 } |
188 |
188 |
189 private boolean checkMD5(MessageDigest digester, DownloadPackage task){ |
189 private boolean checkMD5(MessageDigest digester, DownloadPackage task){ |
190 if(digester != null) { |
190 if(digester != null) { |
191 byte[] messageDigest = digester.digest(); |
191 byte[] messageDigest = digester.digest(); |
192 |
192 |
193 try { |
193 try { |
194 URL url = new URL(task.getURL() + URL_HASH_SUFFIX); |
194 URL url = new URL(task.getURL() + URL_HASH_SUFFIX); |
195 HttpURLConnection conn = (HttpURLConnection)url.openConnection(); |
195 HttpURLConnection conn = (HttpURLConnection)url.openConnection(); |
196 |
196 |
197 byte[] buffer = new byte[1024];//size is large enough to hold the entire hash |
197 byte[] buffer = new byte[1024];//size is large enough to hold the entire hash |
198 BufferedInputStream bis = new BufferedInputStream(conn.getInputStream()); |
198 BufferedInputStream bis = new BufferedInputStream(conn.getInputStream()); |
199 int bytesRead = bis.read(buffer); |
199 int bytesRead = bis.read(buffer); |
200 String hash = null; |
200 String hash = null; |
201 if(bytesRead > -1){ |
201 if(bytesRead > -1){ |
202 hash = new String(buffer, 0, bytesRead); |
202 hash = new String(buffer, 0, bytesRead); |
203 } |
203 } |
204 StringBuffer sb = new StringBuffer(); |
204 StringBuffer sb = new StringBuffer(); |
205 Integer tmp = 0; |
205 Integer tmp = 0; |
206 for(int i = 0; i < messageDigest.length; i++){ |
206 for(int i = 0; i < messageDigest.length; i++){ |
207 tmp = 0xFF & messageDigest[i]; |
207 tmp = 0xFF & messageDigest[i]; |
208 if(tmp < 0xF) sb.append('0'); |
208 if(tmp < 0xF) sb.append('0'); |
209 sb.append(Integer.toHexString(tmp)); |
209 sb.append(Integer.toHexString(tmp)); |
210 } |
210 } |
211 sb.append('\n');//add newline to become identical with the hash file |
211 sb.append('\n');//add newline to become identical with the hash file |
212 |
212 |
213 return hash.equals(sb.toString()); |
213 return hash.equals(sb.toString()); |
214 } catch (IOException e) { |
214 } catch (IOException e) { |
215 e.printStackTrace(); |
215 e.printStackTrace(); |
216 return true; |
216 return true; |
217 } |
217 } |
218 }else{ |
218 }else{ |
219 return true; |
219 return true; |
220 } |
220 } |
221 |
221 |
222 } |
222 } |
223 |
223 |
224 } |
224 } |