Check if we need to download and prevent user from reaching the startgame menu because it needs images from the download hedgeroid
authorXeli
Thu, 01 Sep 2011 14:55:31 +0200
branchhedgeroid
changeset 5671 ba4c3a4c8b09
parent 5669 a806dbe25288
child 5725 e27100a0e2d0
Check if we need to download and prevent user from reaching the startgame menu because it needs images from the download
project_files/Android-build/SDL-android-project/res/values/strings.xml
project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadAsyncTask.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/Downloader/DownloadService.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/MainActivity.java
--- 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 -->
     
--- 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;
--- 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;	
+		}
+
+	}
+
 }
--- 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();
 	}
--- 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);
+			}
 		}
 	};