diff -r 162fec525764 -r 41b0a9955c47 project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadService.java --- 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 downloadTasks = new LinkedList(); - private ArrayList clientList = new ArrayList(); - private Message onRegisterMessage = null; + private Deque downloadTasks = new LinkedList(); - - 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 clients; + + public DownloadTask(DownloadPackage _pack){ + pack = _pack; + clients = new LinkedList(); + } + + 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; } }