project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadService.java
changeset 10017 de822cd3df3a
parent 7584 7831c84cc644
equal deleted inserted replaced
10015:4feced261c68 10017:de822cd3df3a
    35 import android.os.Messenger;
    35 import android.os.Messenger;
    36 import android.os.RemoteException;
    36 import android.os.RemoteException;
    37 import android.widget.RemoteViews;
    37 import android.widget.RemoteViews;
    38 
    38 
    39 public class DownloadService extends Service {
    39 public class DownloadService extends Service {
    40 	public final static String INTENT_TASKID = "taskId";
    40     public final static String INTENT_TASKID = "taskId";
    41 	public final static String INTENT_TASK = "task";
    41     public final static String INTENT_TASK = "task";
    42 
    42 
    43 	public static final String PREF_DOWNLOADED = "downloaded";
    43     public static final String PREF_DOWNLOADED = "downloaded";
    44 	public static final int MSG_CANCEL = 0;
    44     public static final int MSG_CANCEL = 0;
    45 	public static final int MSG_UNREGISTER_CLIENT = 2;
    45     public static final int MSG_UNREGISTER_CLIENT = 2;
    46 	public final static int MSG_ADDTASK = 4;
    46     public final static int MSG_ADDTASK = 4;
    47 
    47 
    48 	public static final int NOTIFICATION_PROCESSING = 0;
    48     public static final int NOTIFICATION_PROCESSING = 0;
    49 	public static final int NOTIFICATION_DONE = 1;
    49     public static final int NOTIFICATION_DONE = 1;
    50 
    50 
    51 	private DownloadAsyncTask asyncExecutor;
    51     private DownloadAsyncTask asyncExecutor;
    52 
    52 
    53 	private DownloadHandler handler = new DownloadHandler();
    53     private DownloadHandler handler = new DownloadHandler();
    54 	private final Messenger messenger = new Messenger(handler);
    54     private final Messenger messenger = new Messenger(handler);
    55 
    55 
    56 	private NotificationManager nM;
    56     private NotificationManager nM;
    57 	private RemoteViews contentView;
    57     private RemoteViews contentView;
    58 
    58 
    59 	private LinkedList<DownloadTask> downloadTasks = new LinkedList<DownloadTask>();
    59     private LinkedList<DownloadTask> downloadTasks = new LinkedList<DownloadTask>();
    60 	private DownloadTask currentTask = null;
    60     private DownloadTask currentTask = null;
    61 
    61 
    62 	public class DownloadHandler extends Handler{
    62     public class DownloadHandler extends Handler{
    63 
    63 
    64 		public void handleMessage(Message msg){
    64         public void handleMessage(Message msg){
    65 			if(msg.obj != null){
    65             if(msg.obj != null){
    66 				DownloadPackage pack = (DownloadPackage) msg.obj;
    66                 DownloadPackage pack = (DownloadPackage) msg.obj;
    67 				DownloadTask task = null;
    67                 DownloadTask task = null;
    68 				Messenger replyToMessenger = msg.replyTo;
    68                 Messenger replyToMessenger = msg.replyTo;
    69 				for(DownloadTask _task : downloadTasks){
    69                 for(DownloadTask _task : downloadTasks){
    70 					if(_task.getPackage().equals(pack)){
    70                     if(_task.getPackage().equals(pack)){
    71 						task = _task;
    71                         task = _task;
    72 						break;
    72                         break;
    73 					}
    73                     }
    74 				}
    74                 }
    75 
    75 
    76 				switch(msg.what){
    76                 switch(msg.what){
    77 				case MSG_ADDTASK:
    77                 case MSG_ADDTASK:
    78 					if(task == null){
    78                     if(task == null){
    79 						task = new DownloadTask(pack);
    79                         task = new DownloadTask(pack);
    80 						downloadTasks.add(task);
    80                         downloadTasks.add(task);
    81 					}
    81                     }
    82 
    82 
    83 					task.addClient(replyToMessenger);
    83                     task.addClient(replyToMessenger);
    84 					runNextTask();
    84                     runNextTask();
    85 					return;
    85                     return;
    86 				case MSG_CANCEL:
    86                 case MSG_CANCEL:
    87 					if(task != null && task.getPackage().equals(pack) && task.getStatus() == TASK_STATE.PENDING){
    87                     if(task != null && task.getPackage().equals(pack) && task.getStatus() == TASK_STATE.PENDING){
    88 						downloadTasks.remove(task);
    88                         downloadTasks.remove(task);
    89 					}
    89                     }
    90 					if(currentTask != null && currentTask.getPackage().equals(pack)){//TODO synchronization problem?
    90                     if(currentTask != null && currentTask.getPackage().equals(pack)){//TODO synchronization problem?
    91 						asyncExecutor.cancel(false);
    91                         asyncExecutor.cancel(false);
    92 					}
    92                     }
    93 					return;
    93                     return;
    94 				case MSG_UNREGISTER_CLIENT:
    94                 case MSG_UNREGISTER_CLIENT:
    95 					if(task != null){
    95                     if(task != null){
    96 						task.removeClient(replyToMessenger);
    96                         task.removeClient(replyToMessenger);
    97 					}
    97                     }
    98 					return;
    98                     return;
    99 				}
    99                 }
   100 			}
   100             }
   101 		}
   101         }
   102 	}
   102     }
   103 
   103 
   104 	public void onCreate(){
   104     public void onCreate(){
   105 		super.onCreate();
   105         super.onCreate();
   106 		nM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
   106         nM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
   107 	}
   107     }
   108 	public IBinder onBind(Intent intent) {
   108     public IBinder onBind(Intent intent) {
   109 		return messenger.getBinder();
   109         return messenger.getBinder();
   110 	}
   110     }
   111 
   111 
   112 	private void runNextTask(){
   112     private void runNextTask(){
   113 		if(asyncExecutor == null){//if (task isnt running right now) ...
   113         if(asyncExecutor == null){//if (task isnt running right now) ...
   114 			currentTask = downloadTasks.poll();
   114             currentTask = downloadTasks.poll();
   115 			if(currentTask != null){
   115             if(currentTask != null){
   116 				asyncExecutor = new DownloadAsyncTask(currentTask);
   116                 asyncExecutor = new DownloadAsyncTask(currentTask);
   117 				asyncExecutor.execute(currentTask.getPackage());
   117                 asyncExecutor.execute(currentTask.getPackage());
   118 			}
   118             }
   119 		}
   119         }
   120 	}
   120     }
   121 
   121 
   122 	public void onDestroy(){
   122     public void onDestroy(){
   123 		super.onDestroy();
   123         super.onDestroy();
   124 		asyncExecutor.cancel(false);	
   124         asyncExecutor.cancel(false);
   125 	}
   125     }
   126 
   126 
   127 	class DownloadTask {
   127     class DownloadTask {
   128 		private final DownloadPackage pack;
   128         private final DownloadPackage pack;
   129 		private TASK_STATE status = TASK_STATE.PENDING;
   129         private TASK_STATE status = TASK_STATE.PENDING;
   130 		private Notification progressNotification, doneNotification;
   130         private Notification progressNotification, doneNotification;
   131 
   131 
   132 		//I expect little to no removeClient calls that's why we go for a list rather than a map
   132         //I expect little to no removeClient calls that's why we go for a list rather than a map
   133 		private final List<Messenger> clients;
   133         private final List<Messenger> clients;
   134 
   134 
   135 		public DownloadTask(DownloadPackage _pack){
   135         public DownloadTask(DownloadPackage _pack){
   136 			pack = _pack;
   136             pack = _pack;
   137 			clients = new LinkedList<Messenger>();
   137             clients = new LinkedList<Messenger>();
   138 		}
   138         }
   139 
   139 
   140 		public void addClient(Messenger messenger){
   140         public void addClient(Messenger messenger){
   141 			clients.add(messenger);
   141             clients.add(messenger);
   142 		}
   142         }
   143 		public void removeClient(Messenger messenger){
   143         public void removeClient(Messenger messenger){
   144 			clients.remove(messenger);
   144             clients.remove(messenger);
   145 		}
   145         }
   146 
   146 
   147 		public DownloadPackage getPackage(){
   147         public DownloadPackage getPackage(){
   148 			return pack;
   148             return pack;
   149 		}
   149         }
   150 
   150 
   151 		public TASK_STATE getStatus(){
   151         public TASK_STATE getStatus(){
   152 			return status;
   152             return status;
   153 		}
   153         }
   154 
   154 
   155 		public void sendMessageToClients(Message msg){
   155         public void sendMessageToClients(Message msg){
   156 			for(Messenger messenger : clients){
   156             for(Messenger messenger : clients){
   157 				try {
   157                 try {
   158 					messenger.send(msg);		
   158                     messenger.send(msg);
   159 				} catch (RemoteException e) {
   159                 } catch (RemoteException e) {
   160 					e.printStackTrace();
   160                     e.printStackTrace();
   161 				}
   161                 }
   162 			}
   162             }
   163 		}
   163         }
   164 
   164 
   165 		/*
   165         /*
   166 		 * Callbacks called from the async tasks
   166          * Callbacks called from the async tasks
   167 		 */
   167          */
   168 
   168 
   169 		//Thread safe method to let clients know the processing is starting and will process int max kbytes
   169         //Thread safe method to let clients know the processing is starting and will process int max kbytes
   170 		public void start(int max){
   170         public void start(int max){
   171 			progressNotification = new Notification(R.drawable.statusbar, getString(R.string.notification_title), System.currentTimeMillis());
   171             progressNotification = new Notification(R.drawable.statusbar, getString(R.string.notification_title), System.currentTimeMillis());
   172 			progressNotification.flags |= Notification.FLAG_ONGOING_EVENT;
   172             progressNotification.flags |= Notification.FLAG_ONGOING_EVENT;
   173 
   173 
   174 			contentView = new RemoteViews(getPackageName(), R.layout.notification);
   174             contentView = new RemoteViews(getPackageName(), R.layout.notification);
   175 			contentView.setProgressBar(R.id.notification_progress, 100, 34, false);
   175             contentView.setProgressBar(R.id.notification_progress, 100, 34, false);
   176 			progressNotification.contentView = contentView;
   176             progressNotification.contentView = contentView;
   177 
   177 
   178 			PendingIntent contentIntent = PendingIntent.getActivity(DownloadService.this, 0, new Intent(DownloadService.this, DownloadListActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK);
   178             PendingIntent contentIntent = PendingIntent.getActivity(DownloadService.this, 0, new Intent(DownloadService.this, DownloadListActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK);
   179 			progressNotification.contentIntent = contentIntent;
   179             progressNotification.contentIntent = contentIntent;
   180 
   180 
   181 			startForeground(NOTIFICATION_PROCESSING, progressNotification);
   181             startForeground(NOTIFICATION_PROCESSING, progressNotification);
   182 
   182 
   183 			Message msg = Message.obtain(null, DownloadFragment.MSG_START, max, 0);
   183             Message msg = Message.obtain(null, DownloadFragment.MSG_START, max, 0);
   184 			sendMessageToClients(msg);
   184             sendMessageToClients(msg);
   185 		}
   185         }
   186 
   186 
   187 		//periodically gets called by the ASyncTask, we can't tell for sure when it's called
   187         //periodically gets called by the ASyncTask, we can't tell for sure when it's called
   188 		public void update(int progress, int max, String fileName){
   188         public void update(int progress, int max, String fileName){
   189 			progress = (progress/1024);
   189             progress = (progress/1024);
   190 
   190 
   191 			contentView.setProgressBar(R.id.notification_progress, max, progress, false);
   191             contentView.setProgressBar(R.id.notification_progress, max, progress, false);
   192 			contentView.setTextViewText(R.id.progressbar_sub, String.format("%dkb/%dkb (Compressed sizes)", progress, max));
   192             contentView.setTextViewText(R.id.progressbar_sub, String.format("%dkb/%dkb (Compressed sizes)", progress, max));
   193 			nM.notify(NOTIFICATION_PROCESSING, progressNotification);
   193             nM.notify(NOTIFICATION_PROCESSING, progressNotification);
   194 
   194 
   195 			sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_UPDATE, progress, max, fileName));
   195             sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_UPDATE, progress, max, fileName));
   196 		}
   196         }
   197 
   197 
   198 		//Call back from the ASync task when the task has either run into an error or finished otherwise
   198         //Call back from the ASync task when the task has either run into an error or finished otherwise
   199 		public void done(int result){
   199         public void done(int result){
   200 			switch(result){
   200             switch(result){
   201 			case DownloadAsyncTask.EXIT_SUCCESS: 	sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_DONE)); break;
   201             case DownloadAsyncTask.EXIT_SUCCESS:    sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_DONE)); break;
   202 			case DownloadAsyncTask.EXIT_CONNERROR:  sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED, DownloadAsyncTask.EXIT_CONNERROR, 0)); break;
   202             case DownloadAsyncTask.EXIT_CONNERROR:  sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED, DownloadAsyncTask.EXIT_CONNERROR, 0)); break;
   203 			case DownloadAsyncTask.EXIT_FNF:		sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED, DownloadAsyncTask.EXIT_FNF, 0)); break;
   203             case DownloadAsyncTask.EXIT_FNF:        sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED, DownloadAsyncTask.EXIT_FNF, 0)); break;
   204 			case DownloadAsyncTask.EXIT_MD5:		sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED, DownloadAsyncTask.EXIT_MD5, 0)); break;
   204             case DownloadAsyncTask.EXIT_MD5:        sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED, DownloadAsyncTask.EXIT_MD5, 0)); break;
   205 			case DownloadAsyncTask.EXIT_URLFAIL:	sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED, DownloadAsyncTask.EXIT_URLFAIL, 0)); break;
   205             case DownloadAsyncTask.EXIT_URLFAIL:    sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_FAILED, DownloadAsyncTask.EXIT_URLFAIL, 0)); break;
   206 			case DownloadAsyncTask.EXIT_CANCELLED:	sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_DONE)); break;
   206             case DownloadAsyncTask.EXIT_CANCELLED:  sendMessageToClients(Message.obtain(handler, DownloadFragment.MSG_DONE)); break;
   207 			}
   207             }
   208 			
   208 
   209 			stopForeground(true);
   209             stopForeground(true);
   210 			nM.cancel(NOTIFICATION_PROCESSING);
   210             nM.cancel(NOTIFICATION_PROCESSING);
   211 
   211 
   212 			String title = getString(R.string.notification_title);
   212             String title = getString(R.string.notification_title);
   213 
   213 
   214 			doneNotification = new Notification(R.drawable.icon, title, System.currentTimeMillis());
   214             doneNotification = new Notification(R.drawable.icon, title, System.currentTimeMillis());
   215 			doneNotification.flags |= Notification.FLAG_AUTO_CANCEL;
   215             doneNotification.flags |= Notification.FLAG_AUTO_CANCEL;
   216 			PendingIntent contentIntent = PendingIntent.getActivity(DownloadService.this, 0, new Intent(DownloadService.this, DownloadListActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK);
   216             PendingIntent contentIntent = PendingIntent.getActivity(DownloadService.this, 0, new Intent(DownloadService.this, DownloadListActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK);
   217 			doneNotification.setLatestEventInfo(DownloadService.this, title, getString(R.string.notification_done) + pack, contentIntent);
   217             doneNotification.setLatestEventInfo(DownloadService.this, title, getString(R.string.notification_done) + pack, contentIntent);
   218 			nM.notify(pack.getId(), doneNotification);
   218             nM.notify(pack.getId(), doneNotification);
   219 
   219 
   220 			asyncExecutor = null;
   220             asyncExecutor = null;
   221 			runNextTask();//see if there are more tasks
   221             runNextTask();//see if there are more tasks
   222 		}
   222         }
   223 
   223 
   224 	}
   224     }
   225 
   225 
   226 	enum TASK_STATE{
   226     enum TASK_STATE{
   227 		RUNNING, FINISHED, PENDING;
   227         RUNNING, FINISHED, PENDING;
   228 	}
   228     }
   229 
   229 
   230 }
   230 }