# 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 @@ Cancel Done Back to main menu + Try again + The download has failed, check the internet connectivity and please try again + Before starting the game we must download some extra files... 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 { + 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); + } } };