project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadService.java
branchhedgeroid
changeset 6350 41b0a9955c47
parent 6343 9df5a486f41e
child 6437 4ed58839b13b
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadService.java	Thu Nov 24 13:40:17 2011 +0100
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadService.java	Thu Nov 24 13:44:30 2011 +0100
@@ -20,11 +20,12 @@
 package org.hedgewars.hedgeroid.Downloader;
 
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.LinkedList;
+import java.util.List;
 
 import org.hedgewars.hedgeroid.MainActivity;
 import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Utils;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -37,104 +38,83 @@
 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 {
-
-	public final static int TASKID_SETUP = 0;
-	public final static int TASKID_CANCEL = 1;
-	public final static int TASKID_ADDTASK = 2;
-
 	public final static String INTENT_TASKID = "taskId";
 	public final static String INTENT_TASK = "task";
 
 	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;
+	public final static int MSG_ADDTASK = 4;
 
 	public static final int NOTIFICATION_PROCESSING = 0;
 	public static final int NOTIFICATION_DONE = 1;
 
 	private DownloadAsyncTask asyncExecutor;
-	private final Messenger messenger = new Messenger(new DownloadHandler());
+
+	private DownloadHandler handler = new DownloadHandler();
+	private final Messenger messenger = new Messenger(handler);
+
 	private NotificationManager nM;
 	private RemoteViews contentView;
-	private Notification notification;
 
-	private LinkedList<DownloadTask> downloadTasks = new LinkedList<DownloadTask>();
-	private ArrayList<Messenger> clientList = new ArrayList<Messenger>();
-	private Message onRegisterMessage = null;
+	private Deque<DownloadTask> downloadTasks = new LinkedList<DownloadTask>();
 
-
-	class DownloadHandler extends Handler{
+	public class DownloadHandler extends Handler{
 
 		public void handleMessage(Message msg){
-			switch(msg.what){
-			case MSG_CANCEL:
-				asyncExecutor.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();
+			if(msg.obj != null){
+				DownloadPackage pack = (DownloadPackage) msg.obj;
+				DownloadTask task = null;
+				Messenger replyToMessenger = msg.replyTo;
+				for(DownloadTask _task : downloadTasks){
+					if(_task.getPackage().equals(pack)){
+						task = _task;
+						break;
 					}
 				}
-				break;
-			case MSG_UNREGISTER_CLIENT:
-				clientList.remove(msg.replyTo);
-				break;
+
+				switch(msg.what){
+				case MSG_ADDTASK:
+					if(task == null){
+						task = new DownloadTask(pack);
+						downloadTasks.add(task);
+					}
+
+					task.addClient(replyToMessenger);
+					runNextTask();
+					return;
+				case MSG_CANCEL:
+					if(task != null && task.getPackage().equals(pack) && task.getStatus() == TASK_STATE.RUNNING){
+						asyncExecutor.cancel(false);
+					}
+					return;
+				case MSG_UNREGISTER_CLIENT:
+					if(task != null){
+						task.removeClient(replyToMessenger);
+					}
+					return;
+				}
 			}
 		}
 	}
+
+	public void onCreate(){
+		super.onCreate();
+		nM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+	}
 	public IBinder onBind(Intent intent) {
 		return messenger.getBinder();
 	}
 
-	/**
-	 * This is the main method which controls how DownloadService and DownloadAsyncTask are running
-	 */
-	public int onStartCommand(Intent intent, int flags, int startId){
-		switch(intent.getIntExtra("taskID", TASKID_SETUP)){
-		case TASKID_SETUP:
-			nM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
-
-			notification = new Notification(R.drawable.statusbar, getString(R.string.notification_title), System.currentTimeMillis());
-			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;
-
-			asyncExecutor = new DownloadAsyncTask(this);
-			break;
-		case TASKID_ADDTASK:
-			//Add downloadtask to the queue
-			DownloadTask task = intent.getParcelableExtra(DownloadService.INTENT_TASK);
-			downloadTasks.offer(task);
-			runNextTask();
-			break;
-		case TASKID_CANCEL:
-			asyncExecutor.cancel(false);
-			break;
-		}		
-		return 0;
-	}
-
-	private synchronized void runNextTask(){
-		if(!asyncExecutor.getStatus().equals(AsyncTask.Status.RUNNING)){//if the task isnt running right now...
-			DownloadTask task = downloadTasks.poll();
-			if(task == null){
-				startForeground(NOTIFICATION_PROCESSING, notification);
-				asyncExecutor.execute(task);
+	private void runNextTask(){
+		if(asyncExecutor == null){//if (task isnt running right now) ...
+			DownloadTask task = downloadTasks.pollFirst();
+			if(task != null){
+				asyncExecutor = new DownloadAsyncTask(task);
+				asyncExecutor.execute(task.getPackage());
 			}
 		}
 	}
@@ -144,59 +124,101 @@
 		asyncExecutor.cancel(false);	
 	}
 
-	/*
-	 * Callbacks called from the async tasks
-	 */
+	class DownloadTask {
+		private final DownloadPackage pack;
+		private TASK_STATE status = TASK_STATE.PENDING;
+		private Notification progressNotification, doneNotification;
+
+		//I expect little to no removeClient calls that's why we go for a list rather than a map
+		private final List<Messenger> clients;
+
+		public DownloadTask(DownloadPackage _pack){
+			pack = _pack;
+			clients = new LinkedList<Messenger>();
+		}
+
+		public void addClient(Messenger messenger){
+			clients.add(messenger);
+		}
+		public void removeClient(Messenger messenger){
+			clients.remove(messenger);
+		}
+
+		public DownloadPackage getPackage(){
+			return pack;
+		}
+
+		public TASK_STATE getStatus(){
+			return status;
+		}
+
+		public void sendMessageToClients(Message msg){
+			for(Messenger messenger : clients){
+				try {
+					messenger.send(msg);		
+				} catch (RemoteException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+
+		/*
+		 * Callbacks called from the async tasks
+		 */
 
-	//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);
-	}
+		//Thread safe method to let clients know the processing is starting and will process int max kbytes
+		public void start(int max){
+			progressNotification = new Notification(R.drawable.statusbar, getString(R.string.notification_title), System.currentTimeMillis());
+			progressNotification.flags |= Notification.FLAG_ONGOING_EVENT;
+
+			contentView = new RemoteViews(getPackageName(), R.layout.notification);
+			contentView.setProgressBar(R.id.notification_progress, 100, 34, false);
+			progressNotification.contentView = contentView;
+
+			PendingIntent contentIntent = PendingIntent.getActivity(DownloadService.this, 0, new Intent(DownloadService.this, DownloadFragment.class), Intent.FLAG_ACTIVITY_NEW_TASK);
+			progressNotification.contentIntent = contentIntent;
+
+			startForeground(NOTIFICATION_PROCESSING, progressNotification);//TODO werkt het?
+
+			Message msg = Message.obtain(null, DownloadFragment.MSG_START, max, 0);
+			sendMessageToClients(msg);
+		}
+
+		//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);
 
-	//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);
+			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, progressNotification);
+
+			sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_UPDATE, 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){
+			if(succesful){
+				sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_DONE));
+			}else sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED));
+			stopForeground(true);
+			nM.cancel(NOTIFICATION_PROCESSING);
+
+			String title = getString(R.string.notification_title);
+
+			doneNotification = new Notification(R.drawable.icon, title, System.currentTimeMillis());
+			doneNotification.flags |= Notification.FLAG_AUTO_CANCEL;
+			PendingIntent contentIntent = PendingIntent.getActivity(DownloadService.this, 0, new Intent(DownloadService.this, DownloadListActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK);
+			doneNotification.setLatestEventInfo(DownloadService.this, title, getString(R.string.notification_done) + pack, contentIntent);
+			nM.notify(pack.getId(), doneNotification);
+
+			asyncExecutor = null;
+			runNextTask();//see if there are more tasks
+		}
+
 	}
 
-	//Call back from the ASync task when the task has either run into an error or finished otherwise
-	public void done(boolean succesful){
-		if(succesful){
-			sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_DONE));
-		}else sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_FAILED));
-		nM.cancel(NOTIFICATION_PROCESSING);
-		stopForeground(true);
-		showDoneNotification();
-		runNextTask();//see if there are more tasks
-	}
-
-
-	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(){
-		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?
-		}
+	enum TASK_STATE{
+		RUNNING, FINISHED, PENDING;
 	}
 
 }