39 import android.util.Log; |
41 import android.util.Log; |
40 import android.widget.RemoteViews; |
42 import android.widget.RemoteViews; |
41 |
43 |
42 public class DownloadService extends Service { |
44 public class DownloadService extends Service { |
43 |
45 |
|
46 public final static int TASKID_SETUP = 0; |
|
47 public final static int TASKID_CANCEL = 1; |
|
48 public final static int TASKID_ADDTASK = 2; |
|
49 |
|
50 public final static String INTENT_TASKID = "taskId"; |
|
51 public final static String INTENT_TASK = "task"; |
|
52 |
44 public static final String PREF_DOWNLOADED = "downloaded"; |
53 public static final String PREF_DOWNLOADED = "downloaded"; |
45 public static final int MSG_CANCEL = 0; |
54 public static final int MSG_CANCEL = 0; |
46 public static final int MSG_REGISTER_CLIENT = 1; |
55 public static final int MSG_REGISTER_CLIENT = 1; |
47 public static final int MSG_UNREGISTER_CLIENT = 2; |
56 public static final int MSG_UNREGISTER_CLIENT = 2; |
48 |
57 |
49 public static final int NOTIFICATION_PROCESSING = 0; |
58 public static final int NOTIFICATION_PROCESSING = 0; |
50 public static final int NOTIFICATION_DONE = 1; |
59 public static final int NOTIFICATION_DONE = 1; |
51 |
60 |
52 private DownloadAsyncTask downloadTask; |
61 private DownloadAsyncTask asyncExecutor; |
53 private final Messenger messenger = new Messenger(new DownloadHandler()); |
62 private final Messenger messenger = new Messenger(new DownloadHandler()); |
54 private NotificationManager nM; |
63 private NotificationManager nM; |
55 private RemoteViews contentView; |
64 private RemoteViews contentView; |
56 private Notification notification; |
65 private Notification notification; |
57 |
66 |
|
67 private LinkedList<DownloadTask> downloadTasks = new LinkedList<DownloadTask>(); |
58 private ArrayList<Messenger> clientList = new ArrayList<Messenger>(); |
68 private ArrayList<Messenger> clientList = new ArrayList<Messenger>(); |
59 private Message onRegisterMessage = null; |
69 private Message onRegisterMessage = null; |
60 |
70 |
61 |
71 |
62 class DownloadHandler extends Handler{ |
72 class DownloadHandler extends Handler{ |
63 |
73 |
64 public void handleMessage(Message msg){ |
74 public void handleMessage(Message msg){ |
65 switch(msg.what){ |
75 switch(msg.what){ |
66 case MSG_CANCEL: |
76 case MSG_CANCEL: |
67 downloadTask.cancel(false); |
77 asyncExecutor.cancel(false); |
68 break; |
78 break; |
69 case MSG_REGISTER_CLIENT: |
79 case MSG_REGISTER_CLIENT: |
70 clientList.add(msg.replyTo); |
80 clientList.add(msg.replyTo); |
71 if(onRegisterMessage != null){ |
81 if(onRegisterMessage != null){ |
72 try { |
82 try { |
80 clientList.remove(msg.replyTo); |
90 clientList.remove(msg.replyTo); |
81 break; |
91 break; |
82 } |
92 } |
83 } |
93 } |
84 } |
94 } |
85 |
95 public IBinder onBind(Intent intent) { |
86 public final static int TASKID_START = 0; |
96 return messenger.getBinder(); |
87 public final static int TASKID_CANCEL = 1; |
97 } |
88 public final static int TASKID_RETRY = 2; |
98 |
89 |
99 /** |
|
100 * This is the main method which controls how DownloadService and DownloadAsyncTask are running |
|
101 */ |
90 public int onStartCommand(Intent intent, int flags, int startId){ |
102 public int onStartCommand(Intent intent, int flags, int startId){ |
91 switch(intent.getIntExtra("taskID", TASKID_START)){ |
103 switch(intent.getIntExtra("taskID", TASKID_SETUP)){ |
92 case TASKID_RETRY: |
104 case TASKID_SETUP: |
93 if(downloadTask != null){ |
|
94 downloadTask.cancel(false); |
|
95 downloadTask = null; |
|
96 } |
|
97 case TASKID_START: |
|
98 nM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); |
105 nM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); |
99 |
106 |
100 notification = new Notification(R.drawable.statusbar, getString(R.string.notification_title), System.currentTimeMillis()); |
107 notification = new Notification(R.drawable.statusbar, getString(R.string.notification_title), System.currentTimeMillis()); |
101 //notification.flags |= Notification.FLAG_ONGOING_EVENT;// | Notification.FLAG_NO_CLEAR | Notification.FLAG_FOREGROUND_SERVICE; |
|
102 notification.flags |= Notification.FLAG_ONGOING_EVENT; |
108 notification.flags |= Notification.FLAG_ONGOING_EVENT; |
103 |
109 |
104 contentView = new RemoteViews(getPackageName(), R.layout.notification); |
110 contentView = new RemoteViews(getPackageName(), R.layout.notification); |
105 contentView.setProgressBar(R.id.notification_progress, 100, 34, false); |
111 contentView.setProgressBar(R.id.notification_progress, 100, 34, false); |
106 notification.contentView = contentView; |
112 notification.contentView = contentView; |
107 |
113 |
108 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, DownloadActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK); |
114 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, DownloadActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK); |
109 notification.contentIntent = contentIntent; |
115 notification.contentIntent = contentIntent; |
110 |
116 |
111 //nM.notify(NOTIFICATION_PROCESSING, notification); |
117 asyncExecutor = new DownloadAsyncTask(this); |
112 startForeground(NOTIFICATION_PROCESSING, notification); |
118 break; |
113 |
119 case TASKID_ADDTASK: |
114 if(downloadTask == null){ |
120 //Add downloadtask to the queue |
115 downloadTask = new DownloadAsyncTask(this); |
121 DownloadTask task = intent.getParcelableExtra(DownloadService.INTENT_TASK); |
116 downloadTask.execute(Utils.getDownloadPath(this)); |
122 downloadTasks.offer(task); |
117 } |
123 runNextTask(); |
118 break; |
124 break; |
119 case TASKID_CANCEL: |
125 case TASKID_CANCEL: |
120 downloadTask.cancel(false); |
126 asyncExecutor.cancel(false); |
121 stopService(); |
|
122 break; |
127 break; |
123 } |
128 } |
124 return 0; |
129 return 0; |
125 } |
130 } |
126 |
131 |
|
132 private synchronized void runNextTask(){ |
|
133 if(!asyncExecutor.getStatus().equals(AsyncTask.Status.RUNNING)){//if the task isnt running right now... |
|
134 DownloadTask task = downloadTasks.poll(); |
|
135 if(task == null){ |
|
136 startForeground(NOTIFICATION_PROCESSING, notification); |
|
137 asyncExecutor.execute(task); |
|
138 } |
|
139 } |
|
140 } |
|
141 |
127 public void onDestroy(){ |
142 public void onDestroy(){ |
128 Log.e("bla", "onDestroy"); |
143 super.onDestroy(); |
129 downloadTask.cancel(false); |
144 asyncExecutor.cancel(false); |
130 } |
|
131 |
|
132 public IBinder onBind(Intent intent) { |
|
133 return messenger.getBinder(); |
|
134 } |
145 } |
135 |
146 |
136 /* |
147 /* |
137 * Thread safe method to let clients know the processing is starting and will process int max kbytes |
148 * Callbacks called from the async tasks |
138 */ |
149 */ |
|
150 |
|
151 //Thread safe method to let clients know the processing is starting and will process int max kbytes |
139 public void start(int max){ |
152 public void start(int max){ |
140 onRegisterMessage = Message.obtain(null, DownloadActivity.MSG_START, max, -1); |
153 onRegisterMessage = Message.obtain(null, DownloadActivity.MSG_START, max, -1); |
141 sendMessageToClients(onRegisterMessage); |
154 sendMessageToClients(onRegisterMessage); |
142 } |
155 } |
143 |
156 |
144 /* |
157 //periodically gets called by the ASyncTask, we can't tell for sure when it's called |
145 * periodically gets called by the ASyncTask, we can't tell for sure when it's called |
|
146 */ |
|
147 public void update(int progress, int max, String fileName){ |
158 public void update(int progress, int max, String fileName){ |
148 progress = (progress/1024); |
159 progress = (progress/1024); |
149 updateNotification(progress, max, fileName); |
160 updateNotification(progress, max, fileName); |
150 |
161 |
151 sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_UPDATE, progress, max, fileName)); |
162 sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_UPDATE, progress, max, fileName)); |
152 } |
163 } |
153 |
164 |
154 /* |
165 //Call back from the ASync task when the task has either run into an error or finished otherwise |
155 * Call back from the ASync task when the task has either run into an error or finished otherwise |
|
156 */ |
|
157 public void done(boolean succesful){ |
166 public void done(boolean succesful){ |
158 if(succesful){ |
167 if(succesful){ |
159 PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(DownloadService.PREF_DOWNLOADED, true).commit(); |
|
160 sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_DONE)); |
168 sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_DONE)); |
161 }else sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_FAILED)); |
169 }else sendMessageToClients(Message.obtain(null, DownloadActivity.MSG_FAILED)); |
162 stopService();//stopService clears all notifications and thus must be called before we show the ready notification |
170 nM.cancel(NOTIFICATION_PROCESSING); |
|
171 stopForeground(true); |
163 showDoneNotification(); |
172 showDoneNotification(); |
164 } |
173 runNextTask();//see if there are more tasks |
165 |
174 } |
166 private void stopService(){ |
175 |
167 nM.cancelAll(); |
176 |
168 stopForeground(true); |
|
169 stopSelf(); |
|
170 } |
|
171 |
|
172 private void updateNotification(int progress, int max, String fileName){ |
177 private void updateNotification(int progress, int max, String fileName){ |
173 |
178 |
174 contentView.setProgressBar(R.id.notification_progress, max, progress, false); |
179 contentView.setProgressBar(R.id.notification_progress, max, progress, false); |
175 contentView.setTextViewText(R.id.progressbar_sub, String.format("%dkb/%dkb (Compressed sizes)", progress, max)); |
180 contentView.setTextViewText(R.id.progressbar_sub, String.format("%dkb/%dkb (Compressed sizes)", progress, max)); |
176 nM.notify(NOTIFICATION_PROCESSING, notification); |
181 nM.notify(NOTIFICATION_PROCESSING, notification); |
177 } |
182 } |
178 |
183 |
179 private void showDoneNotification(){ |
184 private void showDoneNotification(){ |
180 nM.cancelAll(); |
|
181 stopForeground(true); |
|
182 |
|
183 String title = getString(R.string.notification_title); |
185 String title = getString(R.string.notification_title); |
184 |
186 |
185 notification = new Notification(R.drawable.icon, title, System.currentTimeMillis()); |
187 notification = new Notification(R.drawable.icon, title, System.currentTimeMillis()); |
186 notification.flags |= Notification.FLAG_AUTO_CANCEL; |
188 notification.flags |= Notification.FLAG_AUTO_CANCEL; |
187 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK); |
189 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK); |
188 notification.setLatestEventInfo(this, title, getString(R.string.notification_done), contentIntent); |
190 notification.setLatestEventInfo(this, title, getString(R.string.notification_done), contentIntent); |
189 nM.notify(NOTIFICATION_DONE, notification); |
191 nM.notify(NOTIFICATION_DONE, notification); |
190 } |
192 } |
|
193 |
191 private void sendMessageToClients(Message msg){ |
194 private void sendMessageToClients(Message msg){ |
192 for(Messenger m : clientList){ |
195 for(Messenger m : clientList){ |
193 try { |
196 try { |
194 m.send(Message.obtain(msg)); |
197 m.send(Message.obtain(msg)); |
195 } catch (RemoteException e) {}//TODO should we catch this properly? |
198 } catch (RemoteException e) {}//TODO should we catch this properly? |