blob: 3ab830e13dc3b84477b5553ea6427e6bb014ead1 [file] [log] [blame]
Emeric Vigier6119d782012-09-21 18:04:14 -04001/**
2 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
alisionb1763882013-06-18 17:30:51 -04003 * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
Emeric Vigier6119d782012-09-21 18:04:14 -04004 *
5 * Author: Regis Montoya <r3gis.3R@gmail.com>
6 * Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com>
alision11e8e162013-05-28 10:33:14 -04007 * Alexandre Lision <alexandre.lision@savoirfairelinux.com>
Emeric Vigier6119d782012-09-21 18:04:14 -04008 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 * If you own a pjsip commercial license you can also redistribute it
14 * and/or modify it under the terms of the GNU Lesser General Public License
15 * as an android library.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
Emeric Vigiereaf2c492012-09-19 14:38:20 -040025package com.savoirfairelinux.sflphone.service;
26
Emeric Vigier6119d782012-09-21 18:04:14 -040027import java.lang.ref.WeakReference;
alision17052d42013-04-22 10:39:38 -040028import java.util.ArrayList;
29import java.util.HashMap;
alisioncc7bb422013-06-06 15:31:39 -040030import java.util.Iterator;
alision7f18fc82013-05-01 09:37:33 -040031import java.util.List;
alision17052d42013-04-22 10:39:38 -040032import java.util.Map;
alision806e18e2013-06-21 15:30:17 -040033import java.util.Map.Entry;
alision2cb99562013-05-30 17:02:20 -040034import java.util.Random;
Emeric Vigier6119d782012-09-21 18:04:14 -040035
alision2cb99562013-05-30 17:02:20 -040036import android.app.Notification;
37import android.app.NotificationManager;
38import android.app.PendingIntent;
Emeric Vigiereaf2c492012-09-19 14:38:20 -040039import android.app.Service;
alision17052d42013-04-22 10:39:38 -040040import android.content.Context;
Emeric Vigiereaf2c492012-09-19 14:38:20 -040041import android.content.Intent;
alision17052d42013-04-22 10:39:38 -040042import android.content.IntentFilter;
alision7f18fc82013-05-01 09:37:33 -040043import android.os.Bundle;
Emeric Vigier6119d782012-09-21 18:04:14 -040044import android.os.Handler;
45import android.os.HandlerThread;
Emeric Vigiereaf2c492012-09-19 14:38:20 -040046import android.os.IBinder;
Emeric Vigier6119d782012-09-21 18:04:14 -040047import android.os.Looper;
48import android.os.Message;
alision5f899632013-04-22 17:26:56 -040049import android.os.RemoteException;
alision2cb99562013-05-30 17:02:20 -040050import android.support.v4.app.NotificationCompat;
alision17052d42013-04-22 10:39:38 -040051import android.support.v4.content.LocalBroadcastManager;
Emeric Vigiereaf2c492012-09-19 14:38:20 -040052import android.util.Log;
53import android.widget.Toast;
54
alision2cb99562013-05-30 17:02:20 -040055import com.savoirfairelinux.sflphone.R;
alisionf76de3b2013-04-16 15:35:22 -040056import com.savoirfairelinux.sflphone.account.AccountDetailsHandler;
alisione2a38e12013-04-25 14:20:20 -040057import com.savoirfairelinux.sflphone.account.HistoryHandler;
alision2cb99562013-05-30 17:02:20 -040058import com.savoirfairelinux.sflphone.client.SFLPhoneHomeActivity;
Emeric Vigiereaf2c492012-09-19 14:38:20 -040059import com.savoirfairelinux.sflphone.client.SFLphoneApplication;
alision806e18e2013-06-21 15:30:17 -040060import com.savoirfairelinux.sflphone.model.Conference;
alisionfde875f2013-05-28 17:01:54 -040061import com.savoirfairelinux.sflphone.model.SipCall;
alisioncc7bb422013-06-06 15:31:39 -040062import com.savoirfairelinux.sflphone.receivers.IncomingReceiver;
Alexandre Savard713a34d2012-09-26 15:50:41 -040063
Emeric Vigiereaf2c492012-09-19 14:38:20 -040064public class SipService extends Service {
65
66 static final String TAG = "SipService";
67 static final int DELAY = 5000; /* 5 sec */
68 private boolean runFlag = false;
69 private SipServiceThread sipServiceThread;
Emeric Vigier84e05da2012-09-20 14:53:05 -040070 private SFLphoneApplication sflphoneApp;
Emeric Vigier6119d782012-09-21 18:04:14 -040071 private SipServiceExecutor mExecutor;
72 private static HandlerThread executorThread;
73 private CallManagerJNI callManagerJNI;
Emeric Vigier0007dee2012-09-24 11:35:58 -040074 private CallManagerCallBack callManagerCallBack;
Alexandre Savardc1b08fe2012-09-25 16:24:47 -040075 private ConfigurationManagerJNI configurationManagerJNI;
Alexandre Savardfccd1dc2012-10-17 17:31:38 -040076 private ConfigurationManagerCallback configurationManagerCallback;
Emeric Vigier0007dee2012-09-24 11:35:58 -040077 private ManagerImpl managerImpl;
Emeric Vigier6119d782012-09-21 18:04:14 -040078 private boolean isPjSipStackStarted = false;
alisioncc7bb422013-06-06 15:31:39 -040079
alision2cb99562013-05-30 17:02:20 -040080 public static final String NOTIF_CREATION = "notif_creation";
81 public static final String NOTIF_DELETION = "notif_deletion";
alision04a00182013-05-10 17:05:29 -040082
alision2cb99562013-05-30 17:02:20 -040083 private HashMap<String, SipCall> current_calls = new HashMap<String, SipCall>();
alision806e18e2013-06-21 15:30:17 -040084 private HashMap<String, Conference> current_confs = new HashMap<String, Conference>();
85 private IncomingReceiver receiver;
Emeric Vigier6119d782012-09-21 18:04:14 -040086
alision806e18e2013-06-21 15:30:17 -040087 public HashMap<String, Conference> getCurrent_confs() {
88 return current_confs;
89 }
alision43a9b362013-05-01 16:30:15 -040090
91 @Override
92 public boolean onUnbind(Intent i) {
93 super.onUnbind(i);
94 Log.i(TAG, "onUnbind(intent)");
95 return false;
96
97 }
98
99 /* called once by startService() */
100 @Override
101 public void onCreate() {
102 Log.i(TAG, "onCreated");
103 super.onCreate();
104
105 sflphoneApp = (SFLphoneApplication) getApplication();
106 sipServiceThread = new SipServiceThread();
107
108 IntentFilter callFilter = new IntentFilter(CallManagerCallBack.CALL_STATE_CHANGED);
109 callFilter.addAction(CallManagerCallBack.INCOMING_CALL);
110 callFilter.addAction(CallManagerCallBack.NEW_CALL_CREATED);
alision4a0eb092013-05-07 13:52:03 -0400111 callFilter.addAction(ConfigurationManagerCallback.ACCOUNT_STATE_CHANGED);
112 callFilter.addAction(ConfigurationManagerCallback.ACCOUNTS_CHANGED);
alision04a00182013-05-10 17:05:29 -0400113 callFilter.addAction(CallManagerCallBack.INCOMING_TEXT);
alision806e18e2013-06-21 15:30:17 -0400114 callFilter.addAction(CallManagerCallBack.CONF_CREATED);
115 callFilter.addAction(CallManagerCallBack.CONF_REMOVED);
116 callFilter.addAction(CallManagerCallBack.CONF_CHANGED);
alisiondf1dac92013-06-27 17:35:53 -0400117 callFilter.addAction(CallManagerCallBack.RECORD_STATE_CHANGED);
alision806e18e2013-06-21 15:30:17 -0400118 receiver = new IncomingReceiver(this, mBinder);
alision2cb99562013-05-30 17:02:20 -0400119 LocalBroadcastManager.getInstance(this).registerReceiver(receiver, callFilter);
alision2cb99562013-05-30 17:02:20 -0400120
alisioncc7bb422013-06-06 15:31:39 -0400121 getExecutor().execute(new StartRunnable());
122
123 }
alision43a9b362013-05-01 16:30:15 -0400124
125 /* called for each startService() */
126 @Override
127 public int onStartCommand(Intent intent, int flags, int startId) {
128 Log.i(TAG, "onStarted");
129 super.onStartCommand(intent, flags, startId);
130
alision806e18e2013-06-21 15:30:17 -0400131 receiver = new IncomingReceiver(this, mBinder);
alision43a9b362013-05-01 16:30:15 -0400132 if (!runFlag) {
133 sipServiceThread.start();
134 runFlag = true;
135 sflphoneApp.setServiceRunning(true);
136 Toast.makeText(this, "Sflphone Service started", Toast.LENGTH_SHORT).show();
137 }
138
alision907bde72013-06-20 14:40:37 -0400139 return START_NOT_STICKY; /* started and stopped explicitly */
alision43a9b362013-05-01 16:30:15 -0400140 }
141
142 @Override
143 public void onDestroy() {
144 /* called once by stopService() */
145 sipServiceThread.interrupt();
146 sipServiceThread = null;
147 runFlag = false;
alision2cb99562013-05-30 17:02:20 -0400148 unregisterReceiver(receiver);
149
alision43a9b362013-05-01 16:30:15 -0400150 sflphoneApp.setServiceRunning(false);
151 Toast.makeText(this, "Sflphone Service stopped", Toast.LENGTH_SHORT).show();
152 super.onDestroy();
153
154 Log.i(TAG, "onDestroyed");
155 }
156
157 @Override
158 public IBinder onBind(Intent arg0) {
159 Log.i(TAG, "onBound");
160 return mBinder;
161 }
162
163 private static Looper createLooper() {
164 if (executorThread == null) {
165 Log.d(TAG, "Creating new handler thread");
166 // ADT gives a fake warning due to bad parse rule.
167 executorThread = new HandlerThread("SipService.Executor");
168 executorThread.start();
169 }
170 return executorThread.getLooper();
171 }
172
173 public SipServiceExecutor getExecutor() {
174 // create mExecutor lazily
175 if (mExecutor == null) {
176 mExecutor = new SipServiceExecutor(this);
177 }
178 return mExecutor;
179 }
180
181 // Executes immediate tasks in a single executorThread.
182 public static class SipServiceExecutor extends Handler {
183 WeakReference<SipService> handlerService;
184
185 SipServiceExecutor(SipService s) {
186 super(createLooper());
187 handlerService = new WeakReference<SipService>(s);
188 }
189
190 public void execute(Runnable task) {
191 // TODO: add wakelock
192 Message.obtain(this, 0/* don't care */, task).sendToTarget();
193 }
194
195 @Override
196 public void handleMessage(Message msg) {
197 if (msg.obj instanceof Runnable) {
198 executeInternal((Runnable) msg.obj);
199 } else {
200 Log.w(TAG, "can't handle msg: " + msg);
201 }
202 }
203
204 private void executeInternal(Runnable task) {
205 try {
206 task.run();
207 } catch (Throwable t) {
208 Log.e(TAG, "run task: " + task, t);
209 }
210 }
211 }
212
213 private void startPjSipStack() throws SameThreadException {
214 if (isPjSipStackStarted)
215 return;
216
217 try {
218 System.loadLibrary("gnustl_shared");
219 System.loadLibrary("expat");
220 System.loadLibrary("yaml");
221 System.loadLibrary("ccgnu2");
222 System.loadLibrary("crypto");
223 System.loadLibrary("ssl");
224 System.loadLibrary("ccrtp1");
225 System.loadLibrary("dbus");
226 System.loadLibrary("dbus-c++-1");
227 System.loadLibrary("samplerate");
228 System.loadLibrary("codec_ulaw");
229 System.loadLibrary("codec_alaw");
alisiond8c83882013-05-17 17:00:42 -0400230 System.loadLibrary("codec_g722");
alision43a9b362013-05-01 16:30:15 -0400231 System.loadLibrary("speexresampler");
232 System.loadLibrary("sflphone");
233 isPjSipStackStarted = true;
234 } catch (UnsatisfiedLinkError e) {
235 Log.e(TAG, "Problem with the current Pj stack...", e);
236 isPjSipStackStarted = false;
237 return;
238 } catch (Exception e) {
239 Log.e(TAG, "Problem with the current Pj stack...", e);
240 }
241
242 /* get unique instance of managerImpl */
243 managerImpl = SFLPhoneservice.instance();
244
245 /* set static AppPath before calling manager.init */
246 managerImpl.setPath(sflphoneApp.getAppPath());
247
248 callManagerJNI = new CallManagerJNI();
249 callManagerCallBack = new CallManagerCallBack(this);
250 SFLPhoneservice.setCallbackObject(callManagerCallBack);
251
252 configurationManagerJNI = new ConfigurationManagerJNI();
253 configurationManagerCallback = new ConfigurationManagerCallback(this);
254 SFLPhoneservice.setConfigurationCallbackObject(configurationManagerCallback);
255
256 managerImpl.init("");
257 return;
258 }
259
alision2cb99562013-05-30 17:02:20 -0400260 public HashMap<String, SipCall> getCurrent_calls() {
261 return current_calls;
262 }
263
alision43a9b362013-05-01 16:30:15 -0400264 // Enforce same thread contract to ensure we do not call from somewhere else
265 public class SameThreadException extends Exception {
266 private static final long serialVersionUID = -905639124232613768L;
267
268 public SameThreadException() {
269 super("Should be launched from a single worker thread");
270 }
271 }
272
273 public abstract static class SipRunnable implements Runnable {
274 protected abstract void doRun() throws SameThreadException, RemoteException;
275
276 public void run() {
277 try {
278 doRun();
279 } catch (SameThreadException e) {
280 Log.e(TAG, "Not done from same thread");
281 } catch (RemoteException e) {
282 Log.e(TAG, e.toString());
283 }
284 }
285 }
286
287 public abstract static class SipRunnableWithReturn implements Runnable {
288 Object obj = null;
289 boolean done = false;
290
291 protected abstract Object doRun() throws SameThreadException;
292
293 public Object getVal() {
294 return obj;
295 }
296
297 public boolean isDone() {
298 return done;
299 }
300
301 public void run() {
302 try {
303 obj = doRun();
304 done = true;
305 } catch (SameThreadException e) {
306 Log.e(TAG, "Not done from same thread");
307 }
308 }
309 }
310
311 class StartRunnable extends SipRunnable {
312 @Override
313 protected void doRun() throws SameThreadException {
314 startPjSipStack();
315 }
316 }
317
318 private class SipServiceThread extends Thread {
319
320 public SipServiceThread() {
321 super("sipServiceThread");
322 }
323
324 @Override
325 public void run() {
326 Log.i(TAG, "SipService thread running...");
327 SipService sipService = SipService.this;
328 while (sipService.runFlag) {
329 try {
330 Thread.sleep(DELAY);
331 } catch (InterruptedException e) {
332 sipService.runFlag = false;
333 Log.w(TAG, "service thread interrupted!");
334 }
335 }
336 }
337 }
338
339 /* ************************************
340 *
341 * Implement public interface for the service
342 *
343 *
344 * **********************************
345 */
Emeric Vigier6119d782012-09-21 18:04:14 -0400346 private final ISipService.Stub mBinder = new ISipService.Stub() {
347
348 @Override
alisionfde875f2013-05-28 17:01:54 -0400349 public void placeCall(final SipCall call) {
Emeric Vigier6119d782012-09-21 18:04:14 -0400350 getExecutor().execute(new SipRunnable() {
351 @Override
352 protected void doRun() throws SameThreadException {
353 Log.i(TAG, "SipService.placeCall() thread running...");
alision907bde72013-06-20 14:40:37 -0400354 callManagerJNI.placeCall(call.getAccountID(), call.getCallId(), call.getContact().getPhones().get(0).getNumber());
alision2cb99562013-05-30 17:02:20 -0400355 getCurrent_calls().put(call.getCallId(), call);
Emeric Vigier6119d782012-09-21 18:04:14 -0400356 }
357 });
358 }
359
360 @Override
361 public void refuse(final String callID) {
362 getExecutor().execute(new SipRunnable() {
363 @Override
364 protected void doRun() throws SameThreadException {
365 Log.i(TAG, "SipService.refuse() thread running...");
366 callManagerJNI.refuse(callID);
367 }
368 });
369 }
370
371 @Override
372 public void accept(final String callID) {
373 getExecutor().execute(new SipRunnable() {
374 @Override
375 protected void doRun() throws SameThreadException {
376 Log.i(TAG, "SipService.placeCall() thread running...");
377 callManagerJNI.accept(callID);
378 }
379 });
380 }
381
382 @Override
383 public void hangUp(final String callID) {
384 getExecutor().execute(new SipRunnable() {
385 @Override
386 protected void doRun() throws SameThreadException {
387 Log.i(TAG, "SipService.hangUp() thread running...");
388 callManagerJNI.hangUp(callID);
389 }
390 });
391 }
Alexandre Savardc1b08fe2012-09-25 16:24:47 -0400392
393 @Override
Alexandre Savarde9dc8992012-10-26 12:12:27 -0400394 public void hold(final String callID) {
395 getExecutor().execute(new SipRunnable() {
396 @Override
397 protected void doRun() throws SameThreadException {
398 Log.i(TAG, "SipService.hold() thread running...");
399 callManagerJNI.hold(callID);
400 }
401 });
402 }
403
404 @Override
405 public void unhold(final String callID) {
406 getExecutor().execute(new SipRunnable() {
407 @Override
408 protected void doRun() throws SameThreadException {
409 Log.i(TAG, "SipService.unhold() thread running...");
410 callManagerJNI.unhold(callID);
411 }
412 });
413 }
414
415 @Override
Alexandre Savardc1b08fe2012-09-25 16:24:47 -0400416 public void setAudioPlugin(final String audioPlugin) {
417 getExecutor().execute(new SipRunnable() {
alision371b77e2013-04-23 14:51:26 -0400418 @Override
419 protected void doRun() throws SameThreadException {
420 Log.i(TAG, "SipService.setAudioPlugin() thread running...");
421 configurationManagerJNI.setAudioPlugin(audioPlugin);
422 }
Alexandre Savard31d27c62012-10-04 16:05:08 -0400423 });
424 }
425
426 @Override
427 public String getCurrentAudioOutputPlugin() {
428 class CurrentAudioPlugin extends SipRunnableWithReturn {
429 @Override
430 protected String doRun() throws SameThreadException {
431 Log.i(TAG, "SipService.getCurrentAudioOutputPlugin() thread running...");
432 return configurationManagerJNI.getCurrentAudioOutputPlugin();
433 }
alision371b77e2013-04-23 14:51:26 -0400434 }
435 ;
Alexandre Savard31d27c62012-10-04 16:05:08 -0400436
437 CurrentAudioPlugin runInstance = new CurrentAudioPlugin();
438 getExecutor().execute(runInstance);
alision371b77e2013-04-23 14:51:26 -0400439 while (!runInstance.isDone()) {
alision84813a12013-05-27 17:40:39 -0400440 // Log.e(TAG, "Waiting for Nofing");
alision371b77e2013-04-23 14:51:26 -0400441 }
Alexandre Savard7a902bc2012-10-04 16:32:35 -0400442 return (String) runInstance.getVal();
Alexandre Savardc1b08fe2012-09-25 16:24:47 -0400443 }
Alexandre Savard713a34d2012-09-26 15:50:41 -0400444
445 @Override
Alexandre Savard6b85e7e2012-09-27 15:43:14 -0400446 public ArrayList<String> getAccountList() {
Alexandre Savard7a2b2202012-10-04 17:07:33 -0400447 class AccountList extends SipRunnableWithReturn {
448 @Override
449 protected StringVect doRun() throws SameThreadException {
450 Log.i(TAG, "SipService.getAccountList() thread running...");
451 return configurationManagerJNI.getAccountList();
452 }
alision371b77e2013-04-23 14:51:26 -0400453 }
454 ;
Alexandre Savard7a2b2202012-10-04 17:07:33 -0400455 AccountList runInstance = new AccountList();
456 getExecutor().execute(runInstance);
alision371b77e2013-04-23 14:51:26 -0400457 while (!runInstance.isDone()) {
alision84813a12013-05-27 17:40:39 -0400458 // Log.e(TAG, "Waiting for Nofing");
alision371b77e2013-04-23 14:51:26 -0400459 }
Alexandre Savard7a2b2202012-10-04 17:07:33 -0400460 StringVect swigvect = (StringVect) runInstance.getVal();
461
Alexandre Savard6b85e7e2012-09-27 15:43:14 -0400462 ArrayList<String> nativelist = new ArrayList<String>();
Alexandre Savard52a72522012-09-27 16:40:13 -0400463
alision371b77e2013-04-23 14:51:26 -0400464 for (int i = 0; i < swigvect.size(); i++)
465 nativelist.add(swigvect.get(i));
Alexandre Savard52a72522012-09-27 16:40:13 -0400466
Alexandre Savard6b85e7e2012-09-27 15:43:14 -0400467 return nativelist;
alision371b77e2013-04-23 14:51:26 -0400468 }
Alexandre Savard6b85e7e2012-09-27 15:43:14 -0400469
470 @Override
alision371b77e2013-04-23 14:51:26 -0400471 public HashMap<String, String> getAccountDetails(final String accountID) {
Alexandre Savard7a902bc2012-10-04 16:32:35 -0400472 class AccountDetails extends SipRunnableWithReturn {
473 private String id;
alision371b77e2013-04-23 14:51:26 -0400474
475 AccountDetails(String accountId) {
476 id = accountId;
477 }
478
Alexandre Savard7a902bc2012-10-04 16:32:35 -0400479 @Override
480 protected StringMap doRun() throws SameThreadException {
Alexandre Savard7a2b2202012-10-04 17:07:33 -0400481 Log.i(TAG, "SipService.getAccountDetails() thread running...");
Alexandre Savard7a902bc2012-10-04 16:32:35 -0400482 return configurationManagerJNI.getAccountDetails(id);
483 }
alision371b77e2013-04-23 14:51:26 -0400484 }
Alexandre Savard7a902bc2012-10-04 16:32:35 -0400485
486 AccountDetails runInstance = new AccountDetails(accountID);
487 getExecutor().execute(runInstance);
alisionfde875f2013-05-28 17:01:54 -0400488
alision371b77e2013-04-23 14:51:26 -0400489 while (!runInstance.isDone()) {
490 }
491 StringMap swigmap = (StringMap) runInstance.getVal();
Alexandre Savard713a34d2012-09-26 15:50:41 -0400492
Alexandre Savard3bbb4792012-10-05 11:30:01 -0400493 HashMap<String, String> nativemap = AccountDetailsHandler.convertSwigToNative(swigmap);
Alexandre Savard713a34d2012-09-26 15:50:41 -0400494
495 return nativemap;
496 }
Alexandre Savard8b7d4332012-09-30 20:02:11 -0400497
498 @Override
alisioncc7bb422013-06-06 15:31:39 -0400499 public void setAccountDetails(final String accountId, final Map map) {
alision371b77e2013-04-23 14:51:26 -0400500 HashMap<String, String> nativemap = (HashMap<String, String>) map;
Alexandre Savard8b7d4332012-09-30 20:02:11 -0400501
Alexandre Savard3bbb4792012-10-05 11:30:01 -0400502 final StringMap swigmap = AccountDetailsHandler.convertFromNativeToSwig(nativemap);
Alexandre Savard718d49f2012-10-02 15:17:13 -0400503
Alexandre Savard7a2b2202012-10-04 17:07:33 -0400504 getExecutor().execute(new SipRunnable() {
505 @Override
506 protected void doRun() throws SameThreadException {
alisioncc7bb422013-06-06 15:31:39 -0400507
508 configurationManagerJNI.setCredentials(accountId, extractCredentials(map));
Alexandre Savard7a2b2202012-10-04 17:07:33 -0400509 configurationManagerJNI.setAccountDetails(accountId, swigmap);
alisioncc7bb422013-06-06 15:31:39 -0400510
511 convertSwigToNative(configurationManagerJNI.getCredentials(accountId));
512 Log.i(TAG, "SipService.setAccountDetails() thread running...");
513 }
514
515 private VectMap extractCredentials(Map map) {
516 VectMap swigmap = new VectMap();
517 StringMap entry = new StringMap();
518 entry.set(ServiceConstants.CONFIG_ACCOUNT_USERNAME, (String) map.get(ServiceConstants.CONFIG_ACCOUNT_USERNAME));
alision806e18e2013-06-21 15:30:17 -0400519 if ((String) map.get(ServiceConstants.CONFIG_ACCOUNT_REALM) != null)
alisioncc7bb422013-06-06 15:31:39 -0400520 entry.set(ServiceConstants.CONFIG_ACCOUNT_REALM, (String) map.get(ServiceConstants.CONFIG_ACCOUNT_REALM));
521 else
522 entry.set(ServiceConstants.CONFIG_ACCOUNT_REALM, "*");
523 entry.set(ServiceConstants.CONFIG_ACCOUNT_PASSWORD, (String) map.get(ServiceConstants.CONFIG_ACCOUNT_PASSWORD));
524 swigmap.add(entry);
525 return swigmap;
526
Alexandre Savard7a2b2202012-10-04 17:07:33 -0400527 }
528 });
Alexandre Savard8b7d4332012-09-30 20:02:11 -0400529 }
530
alisioncc7bb422013-06-06 15:31:39 -0400531 public ArrayList<HashMap<String, String>> convertSwigToNative(VectMap swigmap) {
532
533 ArrayList<HashMap<String, String>> nativemap = new ArrayList<HashMap<String, String>>();
534 Log.i(TAG, "swigmap size " + swigmap.size());
535 for (int i = 0; i < swigmap.size(); ++i) {
536 Log.i(TAG, "Entry " + i);
537 StringMap tmp = swigmap.get(i);
538 Log.i(TAG, tmp.get(ServiceConstants.CONFIG_ACCOUNT_USERNAME));
alision806e18e2013-06-21 15:30:17 -0400539 // Log.i(TAG, tmp.get(ServiceConstants.CONFIG_ACCOUNT_REALM));
alisioncc7bb422013-06-06 15:31:39 -0400540 Log.i(TAG, tmp.get(ServiceConstants.CONFIG_ACCOUNT_PASSWORD));
541 }
542
543 return nativemap;
544 }
545
Alexandre Savard46036572012-10-05 13:56:49 -0400546 @Override
547 public String addAccount(Map map) {
548 class AddAccount extends SipRunnableWithReturn {
549 StringMap map;
alision371b77e2013-04-23 14:51:26 -0400550
551 AddAccount(StringMap m) {
552 map = m;
553 }
554
Alexandre Savard46036572012-10-05 13:56:49 -0400555 @Override
556 protected String doRun() throws SameThreadException {
557 Log.i(TAG, "SipService.getAccountDetails() thread running...");
558 return configurationManagerJNI.addAccount(map);
559 }
alision371b77e2013-04-23 14:51:26 -0400560 }
Alexandre Savard46036572012-10-05 13:56:49 -0400561
alision371b77e2013-04-23 14:51:26 -0400562 final StringMap swigmap = AccountDetailsHandler.convertFromNativeToSwig((HashMap<String, String>) map);
Alexandre Savard46036572012-10-05 13:56:49 -0400563
564 AddAccount runInstance = new AddAccount(swigmap);
565 getExecutor().execute(runInstance);
alision371b77e2013-04-23 14:51:26 -0400566 while (!runInstance.isDone()) {
alision84813a12013-05-27 17:40:39 -0400567 // Log.e(TAG, "Waiting for Nofing");
alision371b77e2013-04-23 14:51:26 -0400568 }
Alexandre Savard46036572012-10-05 13:56:49 -0400569 String accountId = (String) runInstance.getVal();
570
571 return accountId;
572 }
573
574 @Override
575 public void removeAccount(final String accountId) {
576 getExecutor().execute(new SipRunnable() {
577 @Override
578 protected void doRun() throws SameThreadException {
579 Log.i(TAG, "SipService.setAccountDetails() thread running...");
580 configurationManagerJNI.removeAccount(accountId);
581 }
582 });
583 }
alision5f899632013-04-22 17:26:56 -0400584
alisione2a38e12013-04-25 14:20:20 -0400585 @Override
586 public ArrayList<HashMap<String, String>> getHistory() throws RemoteException {
587 class History extends SipRunnableWithReturn {
588
589 @Override
590 protected VectMap doRun() throws SameThreadException {
591 Log.i(TAG, "SipService.getHistory() thread running...");
alision7f18fc82013-05-01 09:37:33 -0400592
alisione2a38e12013-04-25 14:20:20 -0400593 return configurationManagerJNI.getHistory();
594 }
595 }
596
597 History runInstance = new History();
598 getExecutor().execute(runInstance);
599 while (!runInstance.isDone()) {
alision84813a12013-05-27 17:40:39 -0400600 // Log.w(TAG, "Waiting for getHistory");
alisione2a38e12013-04-25 14:20:20 -0400601 }
alision1005ba12013-06-19 13:52:44 -0400602 Log.i(TAG, "SipService.getHistory() DONE");
alisione2a38e12013-04-25 14:20:20 -0400603 VectMap swigmap = (VectMap) runInstance.getVal();
604
605 ArrayList<HashMap<String, String>> nativemap = HistoryHandler.convertSwigToNative(swigmap);
606
607 return nativemap;
608 }
alision7f18fc82013-05-01 09:37:33 -0400609
alision43a9b362013-05-01 16:30:15 -0400610 /*************************
611 * Transfer related API
612 *************************/
613
alision7f18fc82013-05-01 09:37:33 -0400614 @Override
615 public void transfer(final String callID, final String to) throws RemoteException {
616 getExecutor().execute(new SipRunnable() {
617 @Override
618 protected void doRun() throws SameThreadException, RemoteException {
619 Log.i(TAG, "SipService.transfer() thread running...");
620 if (callManagerJNI.transfer(callID, to)) {
621 Bundle bundle = new Bundle();
622 bundle.putString("CallID", callID);
623 bundle.putString("State", "HUNGUP");
624 Intent intent = new Intent(CallManagerCallBack.CALL_STATE_CHANGED);
alision7f18fc82013-05-01 09:37:33 -0400625 intent.putExtra("com.savoirfairelinux.sflphone.service.newstate", bundle);
alision84813a12013-05-27 17:40:39 -0400626 sendBroadcast(intent);
alision7f18fc82013-05-01 09:37:33 -0400627 } else
628 Log.i(TAG, "NOT OK");
629 }
630 });
631
632 }
alision43a9b362013-05-01 16:30:15 -0400633
alision7f18fc82013-05-01 09:37:33 -0400634 @Override
635 public void attendedTransfer(final String transferID, final String targetID) throws RemoteException {
636 getExecutor().execute(new SipRunnable() {
637 @Override
638 protected void doRun() throws SameThreadException, RemoteException {
alision43a9b362013-05-01 16:30:15 -0400639 Log.i(TAG, "SipService.attendedTransfer() thread running...");
alision7f18fc82013-05-01 09:37:33 -0400640 if (callManagerJNI.attendedTransfer(transferID, targetID)) {
641 Log.i(TAG, "OK");
alision7f18fc82013-05-01 09:37:33 -0400642 } else
643 Log.i(TAG, "NOT OK");
644 }
645 });
alision43a9b362013-05-01 16:30:15 -0400646
647 }
648
649 /*************************
650 * Conference related API
651 *************************/
652
653 @Override
654 public void removeConference(final String confID) throws RemoteException {
655 getExecutor().execute(new SipRunnable() {
656 @Override
657 protected void doRun() throws SameThreadException, RemoteException {
658 Log.i(TAG, "SipService.createConference() thread running...");
659 callManagerJNI.removeConference(confID);
660 }
661 });
662
alision7f18fc82013-05-01 09:37:33 -0400663 }
664
665 @Override
alision43a9b362013-05-01 16:30:15 -0400666 public void joinParticipant(final String sel_callID, final String drag_callID) throws RemoteException {
667 getExecutor().execute(new SipRunnable() {
668 @Override
669 protected void doRun() throws SameThreadException, RemoteException {
670 Log.i(TAG, "SipService.joinParticipant() thread running...");
671 callManagerJNI.joinParticipant(sel_callID, drag_callID);
alision806e18e2013-06-21 15:30:17 -0400672 // Generate a CONF_CREATED callback
alision43a9b362013-05-01 16:30:15 -0400673 }
674 });
675
alision7f18fc82013-05-01 09:37:33 -0400676 }
677
alision7f18fc82013-05-01 09:37:33 -0400678 @Override
alision806e18e2013-06-21 15:30:17 -0400679 public void addParticipant(final SipCall call, final String confID) throws RemoteException {
alision43a9b362013-05-01 16:30:15 -0400680 getExecutor().execute(new SipRunnable() {
681 @Override
682 protected void doRun() throws SameThreadException, RemoteException {
683 Log.i(TAG, "SipService.addParticipant() thread running...");
alision806e18e2013-06-21 15:30:17 -0400684 callManagerJNI.addParticipant(call.getCallId(), confID);
685 current_confs.get(confID).getParticipants().add(call);
alision43a9b362013-05-01 16:30:15 -0400686 }
687 });
688
alision7f18fc82013-05-01 09:37:33 -0400689 }
690
691 @Override
alision43a9b362013-05-01 16:30:15 -0400692 public void addMainParticipant(final String confID) throws RemoteException {
693 getExecutor().execute(new SipRunnable() {
694 @Override
695 protected void doRun() throws SameThreadException, RemoteException {
696 Log.i(TAG, "SipService.addMainParticipant() thread running...");
697 callManagerJNI.addMainParticipant(confID);
698 }
699 });
700
alision7f18fc82013-05-01 09:37:33 -0400701 }
702
703 @Override
alision43a9b362013-05-01 16:30:15 -0400704 public void detachParticipant(final String callID) throws RemoteException {
705 getExecutor().execute(new SipRunnable() {
706 @Override
707 protected void doRun() throws SameThreadException, RemoteException {
708 Log.i(TAG, "SipService.detachParticipant() thread running...");
alision806e18e2013-06-21 15:30:17 -0400709 Log.i(TAG, "Detaching " + callID);
710 Iterator<Entry<String, Conference>> it = current_confs.entrySet().iterator();
711 Log.i(TAG, "current_confs size " + current_confs.size());
712 while (it.hasNext()) {
713 Conference tmp = it.next().getValue();
714 Log.i(TAG, "conf has " + tmp.getParticipants().size() + " participants");
715 if (tmp.contains(callID)) {
716 current_calls.put(callID, tmp.getCall(callID));
717 Log.i(TAG, "Call found and put in current_calls");
718 }
719 }
alision43a9b362013-05-01 16:30:15 -0400720 callManagerJNI.detachParticipant(callID);
721 }
722 });
723
alision7f18fc82013-05-01 09:37:33 -0400724 }
725
726 @Override
alision43a9b362013-05-01 16:30:15 -0400727 public void joinConference(final String sel_confID, final String drag_confID) throws RemoteException {
728 getExecutor().execute(new SipRunnable() {
729 @Override
730 protected void doRun() throws SameThreadException, RemoteException {
731 Log.i(TAG, "SipService.joinConference() thread running...");
732 callManagerJNI.joinConference(sel_confID, drag_confID);
733 }
734 });
735
alision7f18fc82013-05-01 09:37:33 -0400736 }
737
738 @Override
alision43a9b362013-05-01 16:30:15 -0400739 public void hangUpConference(final String confID) throws RemoteException {
740 getExecutor().execute(new SipRunnable() {
741 @Override
742 protected void doRun() throws SameThreadException, RemoteException {
743 Log.i(TAG, "SipService.joinConference() thread running...");
744 callManagerJNI.hangUpConference(confID);
745 }
746 });
747
alision7f18fc82013-05-01 09:37:33 -0400748 }
749
750 @Override
alision43a9b362013-05-01 16:30:15 -0400751 public void holdConference(final String confID) throws RemoteException {
752 getExecutor().execute(new SipRunnable() {
753 @Override
754 protected void doRun() throws SameThreadException, RemoteException {
755 Log.i(TAG, "SipService.holdConference() thread running...");
756 callManagerJNI.holdConference(confID);
757 }
758 });
759
alision7f18fc82013-05-01 09:37:33 -0400760 }
761
762 @Override
alision43a9b362013-05-01 16:30:15 -0400763 public void unholdConference(final String confID) throws RemoteException {
764 getExecutor().execute(new SipRunnable() {
765 @Override
766 protected void doRun() throws SameThreadException, RemoteException {
767 Log.i(TAG, "SipService.unholdConference() thread running...");
768 callManagerJNI.unholdConference(confID);
769 }
770 });
771
alision7f18fc82013-05-01 09:37:33 -0400772 }
773
774 @Override
alisiondf1dac92013-06-27 17:35:53 -0400775 public HashMap<String, Conference> getConferenceList() throws RemoteException {
776// class ConfList extends SipRunnableWithReturn {
777// @Override
778// protected StringVect doRun() throws SameThreadException {
779// Log.i(TAG, "SipService.getConferenceList() thread running...");
780// return callManagerJNI.getConferenceList();
781// }
782// }
783// ;
784// ConfList runInstance = new ConfList();
785// getExecutor().execute(runInstance);
786// while (!runInstance.isDone()) {
787// // Log.w(TAG, "Waiting for getConferenceList");
788// }
789// StringVect swigvect = (StringVect) runInstance.getVal();
790//
791// ArrayList<String> nativelist = new ArrayList<String>();
792//
793// for (int i = 0; i < swigvect.size(); i++)
794// nativelist.add(swigvect.get(i));
795//
796// return nativelist;
797 return current_confs;
alision7f18fc82013-05-01 09:37:33 -0400798 }
799
800 @Override
alision907bde72013-06-20 14:40:37 -0400801 public List getParticipantList(final String confID) throws RemoteException {
802 class PartList extends SipRunnableWithReturn {
803 @Override
804 protected StringVect doRun() throws SameThreadException {
805 Log.i(TAG, "SipService.getAccountList() thread running...");
806 return callManagerJNI.getParticipantList(confID);
807 }
808 }
809 ;
810 PartList runInstance = new PartList();
811 getExecutor().execute(runInstance);
812 while (!runInstance.isDone()) {
813 // Log.w(TAG, "Waiting for getConferenceList");
814 }
815 StringVect swigvect = (StringVect) runInstance.getVal();
816
817 ArrayList<String> nativelist = new ArrayList<String>();
818
819 for (int i = 0; i < swigvect.size(); i++)
820 nativelist.add(swigvect.get(i));
821
822 return nativelist;
alision7f18fc82013-05-01 09:37:33 -0400823 }
alision806e18e2013-06-21 15:30:17 -0400824
alision1005ba12013-06-19 13:52:44 -0400825 @Override
alision7f18fc82013-05-01 09:37:33 -0400826 public String getConferenceId(String callID) throws RemoteException {
alision43a9b362013-05-01 16:30:15 -0400827 Log.e(TAG, "getConferenceList not implemented");
alision7f18fc82013-05-01 09:37:33 -0400828 return null;
829 }
830
831 @Override
alision806e18e2013-06-21 15:30:17 -0400832 public String getConferenceDetails(final String callID) throws RemoteException {
833 class ConfDetails extends SipRunnableWithReturn {
834 @Override
835 protected StringMap doRun() throws SameThreadException {
836 Log.i(TAG, "SipService.getAccountList() thread running...");
837 return callManagerJNI.getConferenceDetails(callID);
838 }
839 }
840 ;
841 ConfDetails runInstance = new ConfDetails();
842 getExecutor().execute(runInstance);
843 while (!runInstance.isDone()) {
844 // Log.w(TAG, "Waiting for getConferenceList");
845 }
846 StringMap swigvect = (StringMap) runInstance.getVal();
847
848 return swigvect.get("CONF_STATE");
alision7f18fc82013-05-01 09:37:33 -0400849 }
850
alision04a00182013-05-10 17:05:29 -0400851 @Override
852 public String getRecordPath() throws RemoteException {
853 class RecordPath extends SipRunnableWithReturn {
854
855 @Override
856 protected String doRun() throws SameThreadException {
857 Log.i(TAG, "SipService.getRecordPath() thread running...");
858 return configurationManagerJNI.getRecordPath();
859 }
860 }
861
862 RecordPath runInstance = new RecordPath();
863 getExecutor().execute(runInstance);
864 while (!runInstance.isDone()) {
alision84813a12013-05-27 17:40:39 -0400865 // Log.w(TAG, "Waiting for getRecordPath");
alision04a00182013-05-10 17:05:29 -0400866 }
867 String path = (String) runInstance.getVal();
868
869 return path;
870 }
871
872 @Override
873 public void setRecordingCall(final String id) throws RemoteException {
874 getExecutor().execute(new SipRunnable() {
875 @Override
876 protected void doRun() throws SameThreadException, RemoteException {
877 Log.i(TAG, "SipService.setRecordingCall() thread running...");
878 callManagerJNI.setRecordingCall(id);
879 }
880 });
881
882 }
alision50fa0722013-06-25 17:29:44 -0400883
884 @Override
alisiondf1dac92013-06-27 17:35:53 -0400885 public boolean isRecording(final String id) throws RemoteException {
886 class IsRecording extends SipRunnableWithReturn {
887
888 @Override
889 protected Boolean doRun() throws SameThreadException {
890 Log.i(TAG, "SipService.isRecording() thread running...");
891 return callManagerJNI.getIsRecording(id);
892 }
893 }
894
895 IsRecording runInstance = new IsRecording();
896 getExecutor().execute(runInstance);
897 while (!runInstance.isDone()) {
898 }
899
900 return (Boolean) runInstance.getVal();
901
902 }
903
904 @Override
alision50fa0722013-06-25 17:29:44 -0400905 public boolean startRecordedFilePlayback(final String filepath) throws RemoteException {
906 getExecutor().execute(new SipRunnable() {
907 @Override
908 protected void doRun() throws SameThreadException, RemoteException {
909 Log.i(TAG, "SipService.setRecordingCall() thread running...");
910 callManagerJNI.startRecordedFilePlayback(filepath);
911 }
912 });
913 return false;
914 }
915
916 @Override
917 public void stopRecordedFilePlayback(final String filepath) throws RemoteException {
918 getExecutor().execute(new SipRunnable() {
919 @Override
920 protected void doRun() throws SameThreadException, RemoteException {
921 Log.i(TAG, "SipService.stopRecordedFilePlayback() thread running...");
922 callManagerJNI.stopRecordedFilePlayback(filepath);
923 }
924 });
925 }
alision04a00182013-05-10 17:05:29 -0400926
927 @Override
928 public void setRecordPath(final String path) throws RemoteException {
929 getExecutor().execute(new SipRunnable() {
930 @Override
931 protected void doRun() throws SameThreadException, RemoteException {
932 Log.i(TAG, "SipService.setRecordingCall() thread running...");
933 configurationManagerJNI.setRecordPath(path);
934 }
935 });
936 }
937
938 @Override
939 public void sendTextMessage(final String callID, final String message, final String from) throws RemoteException {
940 getExecutor().execute(new SipRunnable() {
941 @Override
942 protected void doRun() throws SameThreadException, RemoteException {
943 Log.i(TAG, "SipService.sendTextMessage() thread running...");
944 callManagerJNI.sendTextMessage(callID, message, from);
945 }
946 });
947
948 }
949
alisiond295ec22013-05-17 10:12:13 -0400950 @Override
951 public List getAudioCodecList(String accountID) throws RemoteException {
alision806e18e2013-06-21 15:30:17 -0400952 // class AudioCodecList extends SipRunnableWithReturn {
953 //
954 // @Override
955 // protected IntVect doRun() throws SameThreadException {
956 // Log.i(TAG, "SipService.getAudioCodecList() thread running...");
957 // return configurationManagerJNI.getAudioCodecList();
958 // }
959 // }
960 //
961 // AudioCodecList runInstance = new AudioCodecList();
962 // getExecutor().execute(runInstance);
963 // while (!runInstance.isDone()) {
964 // Log.w(TAG, "Waiting for getAudioCodecList");
965 // }
966 // IntVect swigmap = (IntVect) runInstance.getVal();
967 //
968 // ArrayList<Integer> codecs = AudioHandler.convertSwigToNative(swigmap);
969 //
970 // return codecs;
alision907bde72013-06-20 14:40:37 -0400971 return null;
alisiond295ec22013-05-17 10:12:13 -0400972 }
973
alision9f7a6ec2013-05-24 16:26:26 -0400974 @Override
alisionfde875f2013-05-28 17:01:54 -0400975 public HashMap<String, SipCall> getCallList() throws RemoteException {
alision85704182013-05-29 15:23:03 -0400976 // class CallList extends SipRunnableWithReturn {
977 //
978 // @Override
979 // protected StringVect doRun() throws SameThreadException {
980 // Log.i(TAG, "SipService.getCallList() thread running...");
981 // return callManagerJNI.getCallList();
982 // }
983 // }
984 //
985 // CallList runInstance = new CallList();
986 // getExecutor().execute(runInstance);
987 // while (!runInstance.isDone()) {
988 // Log.w(TAG, "Waiting for getAudioCodecList");
989 // }
990 // StringVect swigmap = (StringVect) runInstance.getVal();
991 //
992 // ArrayList<String> nativemap = new ArrayList<String>();
993 // for (int i = 0; i < swigmap.size(); ++i) {
994 //
995 // String t = swigmap.get(i);
996 // nativemap.add(t);
997 // }
alision9f7a6ec2013-05-24 16:26:26 -0400998
alision2cb99562013-05-30 17:02:20 -0400999 return getCurrent_calls();
alision9f7a6ec2013-05-24 16:26:26 -04001000 }
1001
alision85704182013-05-29 15:23:03 -04001002 @Override
1003 public SipCall getCall(String callID) throws RemoteException {
alision2cb99562013-05-30 17:02:20 -04001004 return getCurrent_calls().get(callID);
1005 }
1006
1007 /***********************
1008 * Notification API
1009 ***********************/
1010 @Override
1011 public void createNotification() throws RemoteException {
1012 makeNotification();
alisioncc7bb422013-06-06 15:31:39 -04001013
alision2cb99562013-05-30 17:02:20 -04001014 }
1015
1016 @Override
1017 public void destroyNotification() throws RemoteException {
1018 removeNotification();
alisioncc7bb422013-06-06 15:31:39 -04001019
alision2cb99562013-05-30 17:02:20 -04001020 }
alisioncc7bb422013-06-06 15:31:39 -04001021
alision2cb99562013-05-30 17:02:20 -04001022 private int NOTIFICATION_ID = new Random().nextInt(1000);
alisioncc7bb422013-06-06 15:31:39 -04001023
alision2cb99562013-05-30 17:02:20 -04001024 private void makeNotification() {
alisioncc7bb422013-06-06 15:31:39 -04001025 if (current_calls.size() == 0) {
alision2cb99562013-05-30 17:02:20 -04001026 return;
1027 }
1028 Intent notificationIntent = new Intent(getApplicationContext(), SFLPhoneHomeActivity.class);
alisioncc7bb422013-06-06 15:31:39 -04001029 PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 007, notificationIntent,
1030 PendingIntent.FLAG_UPDATE_CURRENT);
alision2cb99562013-05-30 17:02:20 -04001031
1032 NotificationManager nm = (NotificationManager) getBaseContext().getSystemService(Context.NOTIFICATION_SERVICE);
1033
1034 NotificationCompat.Builder builder = new NotificationCompat.Builder(getBaseContext());
alisioncc7bb422013-06-06 15:31:39 -04001035 //
1036 // builder.setContent(view);
1037 builder.setContentIntent(contentIntent).setOngoing(true).setSmallIcon(R.drawable.ic_launcher)
1038 .setContentTitle(getCurrent_calls().size() + " ongoing calls").setTicker("Pending calls").setWhen(System.currentTimeMillis())
1039 .setAutoCancel(false);
alision2cb99562013-05-30 17:02:20 -04001040 builder.setPriority(NotificationCompat.PRIORITY_MAX);
1041 Notification n = builder.build();
1042
1043 nm.notify(NOTIFICATION_ID, n);
alisioncc7bb422013-06-06 15:31:39 -04001044
alision2cb99562013-05-30 17:02:20 -04001045 }
1046
1047 public void removeNotification() {
1048 NotificationManager nm = (NotificationManager) getBaseContext().getSystemService(Context.NOTIFICATION_SERVICE);
1049 nm.cancel(NOTIFICATION_ID);
alision85704182013-05-29 15:23:03 -04001050 }
1051
alisiondf1dac92013-06-27 17:35:53 -04001052 @Override
1053 public Conference getCurrentCall() throws RemoteException {
1054 for(SipCall i : current_calls.values()){
1055 if(i.isOngoing()){
1056 Conference tmp = new Conference("-1");
1057 tmp.getParticipants().add(i);
1058 return tmp;
1059 }
1060 }
1061
1062 if(!current_confs.isEmpty()){
1063 return (Conference) current_confs.values().toArray()[0];
1064 }
1065 return null;
1066 }
1067
1068
1069
alision50fa0722013-06-25 17:29:44 -04001070
1071
Emeric Vigier6119d782012-09-21 18:04:14 -04001072 };
Emeric Vigiereaf2c492012-09-19 14:38:20 -04001073}