# HG changeset patch
# User Xeli
# Date 1314881731 -7200
# Node ID ba4c3a4c8b098d96e37010bf9c764610bc7fdfa5
# Parent  a806dbe252882aad16aa1ffb4a3184888b3159e9
Check if we need to download and prevent user from reaching the startgame menu because it needs images from the download

diff -r a806dbe25288 -r ba4c3a4c8b09 project_files/Android-build/SDL-android-project/res/values/strings.xml
--- a/project_files/Android-build/SDL-android-project/res/values/strings.xml	Thu Sep 01 14:54:43 2011 +0200
+++ b/project_files/Android-build/SDL-android-project/res/values/strings.xml	Thu Sep 01 14:55:31 2011 +0200
@@ -19,6 +19,9 @@
     <string name="download_cancel">Cancel</string>
     <string name="download_done">Done</string>
     <string name="download_back">Back to main menu</string>
+    <string name="download_tryagain">Try again</string>
+    <string name="download_failed">The download has failed, check the internet connectivity and please try again</string>
+    <string name="download_userexplain">Before starting the game we must download some extra files...</string>
     
     <!-- start game -->
     
diff -r a806dbe25288 -r ba4c3a4c8b09 project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadActivity.java
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadActivity.java	Thu Sep 01 14:54:43 2011 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadActivity.java	Thu Sep 01 14:55:31 2011 +0200
@@ -33,14 +33,15 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
+import android.preference.PreferenceManager;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.ProgressBar;
 import android.widget.TextView;
+import android.widget.Toast;
 
 public class DownloadActivity extends Activity{
-
 	private Messenger messageService;
 	private boolean boundToService = false;
 	
@@ -51,6 +52,7 @@
 	public static final int MSG_START = 0;
 	public static final int MSG_UPDATE = 1;
 	public static final int MSG_DONE = 2;
+	public static final int MSG_FAILED = 3;
 	private Handler.Callback messageCallback = new Handler.Callback() {
 		
 		public boolean handleMessage(Message msg) {
@@ -58,6 +60,10 @@
 			case MSG_START:
 				progress.setMax(msg.arg1);
 				progress_sub.setText(String.format("%dkb/%dkb\n%s", 0, msg.arg1, ""));
+				positive.setText(R.string.download_background);
+				positive.setOnClickListener(backgroundClicker);
+				negative.setText(R.string.download_cancel);
+				negative.setOnClickListener(cancelClicker);
 				break;
 			case MSG_UPDATE:
 				progress_sub.setText(String.format("%d%% - %dkb/%dkb\n%s",(msg.arg1*100)/msg.arg2, msg.arg1, msg.arg2, msg.obj));
@@ -69,6 +75,17 @@
 				
 				positive.setText(R.string.download_back);
 				positive.setOnClickListener(doneClicker);
+				
+				negative.setVisibility(View.INVISIBLE);
+				break;
+			case MSG_FAILED:
+				progress.setProgress(progress.getMax());
+				progress_sub.setText(R.string.download_failed);
+				positive.setText(R.string.download_back);
+				positive.setOnClickListener(doneClicker);
+				
+				negative.setText(R.string.download_tryagain);
+				negative.setOnClickListener(tryAgainClicker);
 				break;
 			}
 			return false;
@@ -111,9 +128,15 @@
 		}
 	};
 	
+	private OnClickListener tryAgainClicker = new OnClickListener(){
+		public void onClick(View v){
+			bindToService(DownloadService.TASKID_RETRY);
+		}
+	};
+	
 	public void onStart(){
 		super.onStart();
-		bindToService();
+		bindToService(DownloadService.TASKID_START);
 	}
 	
 	public void onStop(){
@@ -140,9 +163,9 @@
 		
 	};
 	
-	private void bindToService(){
+	private void bindToService(int taskId){
 		Intent i = new Intent(getApplicationContext(), DownloadService.class);
-		i.putExtra("taskID", DownloadService.TASKID_START);
+		i.putExtra("taskID", taskId);
 		startService(i);
 		bindService(new Intent(getApplicationContext(), DownloadService.class), connection, Context.BIND_AUTO_CREATE);
 		boundToService = true;
diff -r a806dbe25288 -r ba4c3a4c8b09 project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadAsyncTask.java
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadAsyncTask.java	Thu Sep 01 14:54:43 2011 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadAsyncTask.java	Thu Sep 01 14:55:31 2011 +0200
@@ -19,12 +19,15 @@
 
 package org.hedgewars.mobile.Downloader;
 
+import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
@@ -39,96 +42,171 @@
  */
 public class DownloadAsyncTask extends AsyncTask<String, Object, Long> {
 
+	private final static String URL_WITHOUT_SUFFIX = "http://hedgewars.googlecode.com/files/data_5631.";
+	//private final static String URL_WITHOUT_SUFFIX = "http://www.xelification.com/tmp/firebutton.";
+	private final static String URL_ZIP_SUFFIX = "zip";
+	private final static String URL_HASH_SUFFIX = "hash";
+
 	private DownloadService service;
 	private long lastUpdateMillis = 0;
-	
+
 	public DownloadAsyncTask(DownloadService _service){
 		service = _service;
 	}
-	
+
 	/**
 	 * 
 	 * @param params - 2 Strings, first is the path where the unzipped files will be stored, second is the URL to download from
 	 */
 	protected Long doInBackground(String... params) {
 		HttpURLConnection conn = null;
-		try {
-			String rootZipDest = params[0];
+		MessageDigest digester = null;
+		String rootZipDest = params[0];
+
+		File rootDest = new File(rootZipDest);//TODO check for nullpointer, it hints to the absence of an sdcard
+		rootDest.mkdir();
 
-			File rootDest = new File(rootZipDest);//TODO check for nullpointer, it hints to the absence of an sdcard
-			rootDest.mkdir();
-			
-			URL url = new URL(params[1]);
+		try {
+			URL url = new URL(URL_WITHOUT_SUFFIX + URL_ZIP_SUFFIX);
 			conn = (HttpURLConnection)url.openConnection();
-			String contentType = conn.getContentType();
+		} catch (IOException e) {
+			e.printStackTrace();
+			return -1l;
+		}
+
+		String contentType = conn.getContentType();
+
+		if(contentType == null || contentType.contains("zip")){ //Seeing as we provide the url if the contentType is unknown lets assume zips
+			int bytesDecompressed = 0;
+			ZipEntry entry = null;
+			ZipInputStream input = null;
+			int kbytesToProcess = conn.getContentLength()/1024;
+
+			byte[] buffer = new byte[1024];
+			service.start(kbytesToProcess);
 
-			if(contentType == null || contentType.contains("zip")){ //Seeing as we provide the url if the contentType is unknown lets assume zips
-				ZipInputStream input = new ZipInputStream(conn.getInputStream());
-				int bytesDecompressed = 0;
-				final int kbytesToProcess = conn.getContentLength()/1024;
-				
-				service.start(kbytesToProcess);
-				
-				ZipEntry entry = null;
-				while((entry = input.getNextEntry()) != null){
-					String fileName = entry.getName();
-					
-					if(isCancelled()) break;
-					else if(System.currentTimeMillis() - lastUpdateMillis > 1000){
-						lastUpdateMillis = System.currentTimeMillis();
-						publishProgress(bytesDecompressed, kbytesToProcess, fileName);
+			try {
+				digester = MessageDigest.getInstance("MD5");
+
+			} catch (NoSuchAlgorithmException e1) {
+				e1.printStackTrace();
+			}
+
+			try{
+				input = new ZipInputStream(conn.getInputStream());
+				entry = input.getNextEntry();	
+			}catch(IOException e){
+				e.printStackTrace();
+				if(conn != null) conn.disconnect();
+				return -1l;
+			}
+
+			while(entry != null){
+				if(isCancelled()) break;
+
+				String fileName = entry.getName();
+				File f = new File(rootZipDest + fileName);
+				bytesDecompressed += entry.getCompressedSize();
+
+				if(entry.isDirectory()){
+					f.mkdir();
+				}else{
+					if(f.exists()){
+						f.delete();
 					}
-					
-					Log.e("bla", fileName);
-					bytesDecompressed += entry.getCompressedSize();
-					
-					File f = new File(rootZipDest + fileName);
+
+					FileOutputStream output = null;
+					try {
+						f.createNewFile();
+						output = new FileOutputStream(f);
 
-					if(entry.isDirectory()){
-						f.mkdir();
-					}else{
-						if(f.exists()){
-							f.delete();
+						int count = 0;
+						while((count = input.read(buffer)) != -1){
+							output.write(buffer, 0, count);
+							digester.update(buffer, 0, count);
+							if(System.currentTimeMillis() - lastUpdateMillis > 1000){
+								lastUpdateMillis = System.currentTimeMillis();
+								publishProgress(bytesDecompressed, kbytesToProcess, fileName);
+							}
 						}
-
+						output.flush();
+						input.closeEntry();
+					} catch (FileNotFoundException e) {
+						e.printStackTrace();
+						if(conn != null) conn.disconnect();
+						return -1l;
+					} catch (IOException e) {
+						e.printStackTrace();
+						if(conn != null) conn.disconnect();
+						return -1l;
+					}finally{
 						try {
-							f.createNewFile();
-							FileOutputStream out = new FileOutputStream(f);
-
-							byte[] buffer = new byte[1024];
-							int count = 0;
-							while((count = input.read(buffer)) != -1){
-								out.write(buffer, 0, count);
-							}
-							out.flush();
-							out.close();
-							input.closeEntry();
-						} catch (FileNotFoundException e) {
-							e.printStackTrace();
-						} catch (IOException e) {
-							e.printStackTrace();
-						}
+							if( output != null) output.close();
+						} catch (IOException e) {}
 					}
 				}
+				try{
+					entry = input.getNextEntry();
+				}catch(IOException e){
+					e.printStackTrace();
+					if(conn != null) conn.disconnect();
+					return -1l;
+				}
+			}//end while(entry != null)
+
+			try {
 				input.close();
-			}else{
-				Log.e("bla", "contenttype = " + contentType);
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-		}finally{
-			if(conn != null) conn.disconnect();
-		}
-		return null;
+			} catch (IOException e) {}
+		}//end if contentType == "zip"
+
+		if(conn != null) conn.disconnect();
+
+		if(checkMD5(digester))return 0l;
+		else return -1l;
 	}
-	
-	//TODO propper result handling
+
+	//TODO proper result handling
 	protected void onPostExecute(Long result){
-		service.done(true);
+		service.done(result > -1l);
 	}
-	
+
 	protected void onProgressUpdate(Object...objects){
 		service.update((Integer)objects[0], (Integer)objects[1], (String)objects[2]);
 	}
 
+	private boolean checkMD5(MessageDigest digester){
+		if(digester != null) {
+			byte[] messageDigest = digester.digest();
+
+			try {
+				URL url = new URL(URL_WITHOUT_SUFFIX + URL_HASH_SUFFIX);
+				HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+
+				byte[] buffer = new byte[1024];//size is large enough to hold the entire hash
+				BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
+				int bytesRead = bis.read(buffer);
+				if(bytesRead > -1){
+					String hash = new String(buffer, 0, bytesRead);
+					StringBuffer sb = new StringBuffer();
+					Integer tmp = 0;
+					for(int i = 0; i < messageDigest.length; i++){
+						tmp = 0xFF & messageDigest[i];
+						if(tmp < 0xF) sb.append('0');
+						sb.append(Integer.toHexString(tmp));
+					}
+					sb.append('\n');//add newline to become identical with the hash file
+					
+					return hash.equals(sb.toString());
+				}
+				return false;
+			} catch (IOException e) {
+				e.printStackTrace();
+				return false;
+			}
+		}else{
+			return false;	
+		}
+
+	}
+
 }
diff -r a806dbe25288 -r ba4c3a4c8b09 project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadService.java
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadService.java	Thu Sep 01 14:54:43 2011 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadService.java	Thu Sep 01 14:55:31 2011 +0200
@@ -35,12 +35,13 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
+import android.preference.PreferenceManager;
 import android.util.Log;
 import android.widget.RemoteViews;
 
 public class DownloadService extends Service {
 
-	private final static String URL = "http://hedgewars.googlecode.com/files/data_5631.zip";
+	public static final String PREF_DOWNLOADED = "downloaded";
 	public static final int MSG_CANCEL = 0;
 	public static final int MSG_REGISTER_CLIENT = 1;
 	public static final int MSG_UNREGISTER_CLIENT = 2;
@@ -84,9 +85,15 @@
 
 	public final static int TASKID_START = 0;
 	public final static int TASKID_CANCEL = 1;
+	public final static int TASKID_RETRY = 2;
 	
 	public int onStartCommand(Intent intent, int flags, int startId){
 		switch(intent.getIntExtra("taskID", TASKID_START)){
+		case TASKID_RETRY:
+			if(downloadTask != null){
+				downloadTask.cancel(false);
+				downloadTask = null;
+			}
 		case TASKID_START:
 			nM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
 
@@ -106,7 +113,7 @@
 
 			if(downloadTask == null){
 				downloadTask = new DownloadAsyncTask(this);
-				downloadTask.execute(Utils.getDownloadPath(this), URL);
+				downloadTask.execute(Utils.getDownloadPath(this));
 			}	
 			break;
 		case TASKID_CANCEL:
@@ -128,21 +135,30 @@
 
 	/*
 	 * Thread safe method to let clients know the processing is starting and will process int max kbytes
-	 * 
 	 */
 	public void start(int max){
 		onRegisterMessage = Message.obtain(null, DownloadActivity.MSG_START, max, -1);
 		sendMessageToClients(onRegisterMessage);
 	}
 
+	/*
+	 * periodically gets called by the ASyncTask, we can't tell for sure when it's called
+	 */
 	public void update(int progress, int max, String fileName){
 		progress = (progress/1024);
 		updateNotification(progress, max, fileName);
 
 		sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_UPDATE, progress, max, fileName));
 	}
+	
+	/*
+	 * Call back from the ASync task when the task has either run into an error or finished otherwise
+	 */
 	public void done(boolean succesful){
-		sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_DONE));
+		if(succesful){
+			PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(DownloadService.PREF_DOWNLOADED, true).commit();
+			sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_DONE));
+		}else sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_FAILED));
 		stopService();//stopService clears all notifications and thus must be called before we show the ready notification
 		showDoneNotification();
 	}
diff -r a806dbe25288 -r ba4c3a4c8b09 project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/MainActivity.java
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/MainActivity.java	Thu Sep 01 14:54:43 2011 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/MainActivity.java	Thu Sep 01 14:55:31 2011 +0200
@@ -19,13 +19,16 @@
 package org.hedgewars.mobile;
 
 import org.hedgewars.mobile.Downloader.DownloadActivity;
+import org.hedgewars.mobile.Downloader.DownloadService;
 
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
+import android.preference.PreferenceManager;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
+import android.widget.Toast;
 
 public class MainActivity extends Activity {
 
@@ -52,7 +55,12 @@
 
 	private OnClickListener startGameClicker = new OnClickListener(){
 		public void onClick(View v){
-			startActivity(new Intent(getApplicationContext(), StartGameActivity.class));
+			if(PreferenceManager.getDefaultSharedPreferences(MainActivity.this).getBoolean(DownloadService.PREF_DOWNLOADED, false))
+				startActivity(new Intent(getApplicationContext(), StartGameActivity.class));
+			else {
+				Toast.makeText(MainActivity.this, R.string.download_userexplain, Toast.LENGTH_LONG).show();
+				startActivityForResult(new Intent(getApplicationContext(), DownloadActivity.class), 0);
+			}
 		}
 	};