# HG changeset patch
# User Xeli
# Date 1309883238 -7200
# Node ID 4ae1b082e4ba25c3d68ae5950f08c3864dc8a60c
# Parent 5caae9d7e12e74d6ac1f2558252014036edea880
Added download functionality and changed some icons
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/AndroidManifest.xml
--- a/project_files/Android-build/SDL-android-project/AndroidManifest.xml Tue Jul 05 18:23:54 2011 +0200
+++ b/project_files/Android-build/SDL-android-project/AndroidManifest.xml Tue Jul 05 18:27:18 2011 +0200
@@ -1,17 +1,33 @@
+
+
+
-
+ android:theme="@android:style/Theme"
+ android:launchMode="singleTask">
+
+
+
+
+
+
+
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/default.properties
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/default.properties Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/default.properties.orig
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/default.properties.orig Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-9
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/local.properties
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/local.properties Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/home/richard/SoftDev/android/android-sdk-linux_86
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/res/drawable-mdpi/statusbar.png
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/statusbar.png has changed
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/res/layout/download.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/download.xml Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/res/layout/main.xml
--- a/project_files/Android-build/SDL-android-project/res/layout/main.xml Tue Jul 05 18:23:54 2011 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/main.xml Tue Jul 05 18:27:18 2011 +0200
@@ -9,5 +9,18 @@
android:layout_height="wrap_content"
android:text="Hello World, SDLActivity"
/>
+
+
+
+
+
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/res/layout/notification.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/notification.xml Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/res/values/strings.xml
--- a/project_files/Android-build/SDL-android-project/res/values/strings.xml Tue Jul 05 18:23:54 2011 +0200
+++ b/project_files/Android-build/SDL-android-project/res/values/strings.xml Tue Jul 05 18:27:18 2011 +0200
@@ -1,4 +1,18 @@
- SDL App
+ Hedgewars
+
+
+ There\'s been an error when accessing the sdcard, is it connected to another computer?
+
+
+ Downloading hedgewars files...
+ Success - Download complete
+
+
+ Continue in background
+ Cancel
+ Done
+ Back to main menu
+
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/DownloadActivity.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/DownloadActivity.java Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,139 @@
+package org.hedgewars.mobile;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+public class DownloadActivity extends Activity{
+
+ private Messenger messageService;
+ private boolean boundToService = false;
+
+ private TextView progress_sub;
+ private ProgressBar progress;
+ private Button positive, negative;
+
+ public static final int MSG_START = 0;
+ public static final int MSG_UPDATE = 1;
+ public static final int MSG_DONE = 2;
+ private Handler.Callback messageCallback = new Handler.Callback() {
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch(msg.what){
+ case MSG_START:
+ progress.setMax(msg.arg1);
+ progress_sub.setText(String.format("%dkb/%dkb\n%s", 0, msg.arg1, ""));
+ 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));
+ progress.setProgress(msg.arg1);
+ break;
+ case MSG_DONE:
+ progress.setProgress(progress.getMax());
+ progress_sub.setText(R.string.download_done);
+
+ positive.setText(R.string.download_back);
+ positive.setOnClickListener(doneClicker);
+ break;
+ }
+ return false;
+ }
+ };
+ private Handler messageHandler = new Handler(messageCallback);
+ private Messenger messenger = new Messenger(messageHandler);
+
+ public void onCreate(Bundle savedInstanceState){
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.download);
+
+ progress_sub = (TextView)findViewById(R.id.progressbar_sub);
+ progress = (ProgressBar)findViewById(R.id.progressbar);
+
+ positive = (Button) findViewById(R.id.background);
+ negative = (Button) findViewById(R.id.cancelDownload);
+ positive.setOnClickListener(backgroundClicker);
+ negative.setOnClickListener(cancelClicker);
+
+ }
+
+ private OnClickListener backgroundClicker = new OnClickListener(){
+ public void onClick(View v){
+ finish();
+ }
+ };
+ private OnClickListener cancelClicker = new OnClickListener(){
+ public void onClick(View v){
+ Intent i = new Intent(getApplicationContext(), DownloadService.class);
+ i.putExtra("taskID", DownloadService.TASKID_CANCEL);
+ startService(i);
+ finish();
+ }
+ };
+ private OnClickListener doneClicker = new OnClickListener(){
+ public void onClick(View v){
+ finish();
+ startActivity(new Intent(getApplicationContext(), MainActivity.class));
+ }
+ };
+
+ public void onStart(){
+ super.onStart();
+ bindToService();
+ }
+
+ public void onStop(){
+ super.onStop();
+ unBindFromService();
+ }
+
+ private ServiceConnection connection = new ServiceConnection(){
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ messageService = new Messenger(service);
+
+ try{
+ Message msg = Message.obtain(null, DownloadService.MSG_REGISTER_CLIENT);
+ msg.replyTo = messenger;
+ messageService.send(msg);
+
+ }catch (RemoteException e){}
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ messageService = null;
+ }
+
+ };
+
+ private void bindToService(){
+ Intent i = new Intent(getApplicationContext(), DownloadService.class);
+ i.putExtra("taskID", DownloadService.TASKID_START);
+ startService(i);
+ bindService(new Intent(getApplicationContext(), DownloadService.class), connection, Context.BIND_AUTO_CREATE);
+ boundToService = true;
+ }
+
+ private void unBindFromService(){
+ if(boundToService){
+ boundToService = false;
+ unbindService(connection);
+ }
+ }
+}
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/DownloadAsyncTask.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/DownloadAsyncTask.java Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,111 @@
+package org.hedgewars.mobile;
+
+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.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import android.os.AsyncTask;
+import android.util.Log;
+/**
+ * This is an AsyncTask which will download a zip from an URL and unzip it to a specified path
+ *
+ * a typical call to start the task would be new DownloadAsyncTask().execute(getExternalStorage(), "www.hedgewars.org/data.zip");
+ * @author Xeli
+ *
+ */
+public class DownloadAsyncTask extends AsyncTask {
+
+ 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];
+
+ URL url = new URL(params[1]);
+ conn = (HttpURLConnection)url.openConnection();
+ String contentType = conn.getContentType();
+
+ 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);
+ }
+
+ bytesDecompressed += entry.getCompressedSize();
+
+ File f = new File(rootZipDest + fileName);
+
+ if(entry.isDirectory()){
+ f.mkdir();
+ }else{
+ if(f.exists()){
+ f.delete();
+ }
+
+ 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();
+ }
+ }
+ }
+ input.close();
+ }else{
+ Log.e("bla", "contenttype = " + contentType);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }finally{
+ if(conn != null) conn.disconnect();
+ }
+ return null;
+ }
+
+ //TODO propper result handling
+ protected void onPostExecute(Long result){
+ service.done(true);
+ }
+
+ protected void onProgressUpdate(Object...objects){
+ service.update((Integer)objects[0], (Integer)objects[1], (String)objects[2]);
+ }
+
+}
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/DownloadService.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/DownloadService.java Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,171 @@
+package org.hedgewars.mobile;
+
+import java.io.File;
+import java.util.ArrayList;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+
+public class DownloadService extends Service {
+
+ private final static String URL = "http://www.xelification.com/tmp/data.zip";
+ public static final int MSG_CANCEL = 0;
+ public static final int MSG_REGISTER_CLIENT = 1;
+ public static final int MSG_UNREGISTER_CLIENT = 2;
+
+ public static final int NOTIFICATION_PROCESSING = 0;
+ public static final int NOTIFICATION_DONE = 1;
+
+ private DownloadAsyncTask downloadTask;
+ private final Messenger messenger = new Messenger(new DownloadHandler());
+ private NotificationManager nM;
+ private RemoteViews contentView;
+ private Notification notification;
+
+ private ArrayList clientList = new ArrayList();
+ private Message onRegisterMessage = null;
+
+
+ class DownloadHandler extends Handler{
+
+ public void handleMessage(Message msg){
+ switch(msg.what){
+ case MSG_CANCEL:
+ downloadTask.cancel(false);
+ break;
+ case MSG_REGISTER_CLIENT:
+ clientList.add(msg.replyTo);
+ if(onRegisterMessage != null){
+ try {
+ msg.replyTo.send(Message.obtain(onRegisterMessage));
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ break;
+ case MSG_UNREGISTER_CLIENT:
+ clientList.remove(msg.replyTo);
+ break;
+ }
+ }
+ }
+
+ public final static int TASKID_START = 0;
+ public final static int TASKID_CANCEL = 1;
+
+ public int onStartCommand(Intent intent, int flags, int startId){
+ switch(intent.getIntExtra("taskID", TASKID_START)){
+ case TASKID_START:
+ nM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ notification = new Notification(R.drawable.statusbar, getString(R.string.notification_title), System.currentTimeMillis());
+ //notification.flags |= Notification.FLAG_ONGOING_EVENT;// | Notification.FLAG_NO_CLEAR | Notification.FLAG_FOREGROUND_SERVICE;
+ notification.flags |= Notification.FLAG_ONGOING_EVENT;
+
+ contentView = new RemoteViews(getPackageName(), R.layout.notification);
+ contentView.setProgressBar(R.id.notification_progress, 100, 34, false);
+ notification.contentView = contentView;
+
+ PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, DownloadActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK);
+ notification.contentIntent = contentIntent;
+
+ //nM.notify(NOTIFICATION_PROCESSING, notification);
+ startForeground(NOTIFICATION_PROCESSING, notification);
+
+ if(downloadTask == null){
+ downloadTask = new DownloadAsyncTask(this);
+ downloadTask.execute(getDownloadPath(this), URL);
+ }
+ break;
+ case TASKID_CANCEL:
+ downloadTask.cancel(false);
+ stopService();
+ break;
+ }
+ return 0;
+ }
+
+ public void onDestroy(){
+ Log.e("bla", "onDestroy");
+ downloadTask.cancel(false);
+ }
+
+ public IBinder onBind(Intent intent) {
+ return messenger.getBinder();
+ }
+
+ /*
+ * 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);
+ }
+
+ 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));
+ }
+ public void done(boolean succesful){
+ sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_DONE));
+ stopService();//stopService clears all notifications and thus must be called before we show the ready notification
+ showDoneNotification();
+ }
+
+ private void stopService(){
+ nM.cancelAll();
+ stopForeground(true);
+ stopSelf();
+ }
+
+ private void updateNotification(int progress, int max, String fileName){
+
+ contentView.setProgressBar(R.id.notification_progress, max, progress, false);
+ contentView.setTextViewText(R.id.progressbar_sub, String.format("%dkb/%dkb (Compressed sizes)", progress, max));
+ nM.notify(NOTIFICATION_PROCESSING, notification);
+ }
+
+ private void showDoneNotification(){
+ nM.cancelAll();
+ stopForeground(true);
+
+ String title = getString(R.string.notification_title);
+
+ notification = new Notification(R.drawable.icon, title, System.currentTimeMillis());
+ notification.flags |= Notification.FLAG_AUTO_CANCEL;
+ PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK);
+ notification.setLatestEventInfo(this, title, getString(R.string.notification_done), contentIntent);
+ nM.notify(NOTIFICATION_DONE, notification);
+ }
+ private void sendMessageToClients(Message msg){
+ for(Messenger m : clientList){
+ try {
+ m.send(Message.obtain(msg));
+ } catch (RemoteException e) {}//TODO should we catch this properly?
+ }
+ }
+ public static String getDownloadPath(Context c){
+ File f = c.getExternalCacheDir();
+ if(f != null){
+ return f.getAbsolutePath();
+ }else{
+ Toast.makeText(c, R.string.sdcard_not_mounted, Toast.LENGTH_LONG);
+ return null;
+ }
+ }
+}
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/DownloadThread.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/DownloadThread.java Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,13 @@
+package org.hedgewars.mobile;
+
+public class DownloadThread extends Thread{
+
+ public DownloadThread(){
+
+ }
+
+ public void run(){
+
+ }
+
+}
diff -r 5caae9d7e12e -r 4ae1b082e4ba project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/MainActivity.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/mobile/MainActivity.java Tue Jul 05 18:27:18 2011 +0200
@@ -0,0 +1,39 @@
+package org.hedgewars.mobile;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+public class MainActivity extends Activity {
+
+ Button downloader, startGame;
+
+ public void onCreate(Bundle sis){
+ super.onCreate(sis);
+ setContentView(R.layout.main);
+
+ downloader = (Button)findViewById(R.id.downloader);
+ startGame = (Button)findViewById(R.id.startGame);
+
+ downloader.setOnClickListener(downloadClicker);
+ startGame.setOnClickListener(startGameClicker);
+ }
+
+
+
+ private OnClickListener downloadClicker = new OnClickListener(){
+ public void onClick(View v){
+ startActivityForResult(new Intent(getApplicationContext(), DownloadActivity.class), 0);
+ }
+ };
+
+ private OnClickListener startGameClicker = new OnClickListener(){
+ public void onClick(View v){
+ startActivity(new Intent(getApplicationContext(), SDLActivity.class));
+ }
+ };
+
+}