diff --git a/.classpath b/.classpath
index 73e3fe0d3..d150c0422 100644
--- a/.classpath
+++ b/.classpath
@@ -6,6 +6,7 @@
+
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1c7bdc86f..7e38ea7ca 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -42,7 +42,13 @@
-
+
+
+
+
+
@@ -103,6 +109,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/conferencing.xml b/res/layout/conferencing.xml
new file mode 100644
index 000000000..5a78dfc63
--- /dev/null
+++ b/res/layout/conferencing.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/incall_view.xml b/res/layout/incall_view.xml
index 74a4bd303..714cf5cbf 100644
--- a/res/layout/incall_view.xml
+++ b/res/layout/incall_view.xml
@@ -24,9 +24,7 @@
-
+
@@ -34,8 +32,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
diff --git a/res/values/custom.xml b/res/values/custom.xml
index a5602db26..abc5529e9 100644
--- a/res/values/custom.xml
+++ b/res/values/custom.xml
@@ -10,7 +10,7 @@
false
true
true
- false
+ true
true
true
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f715b4e77..4de957040 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1,6 +1,14 @@
+ DTMFs
+
+ You host a conference
+ You are part of it
+ Go out
+ You are out of it
+ Go in
+
Audio hacks
Use specific mode hack
0=MODE_NORMAL (default), 2=MODE_IN_CALL
diff --git a/src/org/linphone/ConferenceActivity.java b/src/org/linphone/ConferenceActivity.java
new file mode 100644
index 000000000..7178ed79d
--- /dev/null
+++ b/src/org/linphone/ConferenceActivity.java
@@ -0,0 +1,408 @@
+/*
+AbstractLinphoneConferenceActivity.java
+Copyright (C) 2011 Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+package org.linphone;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.linphone.LinphoneSimpleListener.LinphoneOnCallStateChangedListener;
+import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCore;
+import org.linphone.core.LinphoneCoreException;
+import org.linphone.core.LinphoneCall.State;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ListActivity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class ConferenceActivity extends ListActivity implements
+ LinphoneOnCallStateChangedListener, Comparator,
+ OnClickListener {
+
+ private View confHeaderView;
+
+ // Start Override to test block
+ protected LinphoneCore lc() {
+ return LinphoneManager.getLc();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected List getInitialCalls() {
+ return lc().getCalls();
+ }
+
+ // End override to test block
+
+ private static final int ACTIVE_BG_COLOR = Color.parseColor("#777777");
+ public static final int INACTIVE_BG_COLOR = Color.BLACK;
+ public static final int INCOMING_BG_COLOR = Color.parseColor("#336600");
+ public static final int CONFERENCE_BG_COLOR = Color.parseColor("#444444");
+ private static final int numpad_dialog_id = 1;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setContentView(R.layout.conferencing);
+ super.onCreate(savedInstanceState);
+ confHeaderView = findViewById(R.id.conf_header);
+ confHeaderView.findViewById(R.id.terminate_conference)
+ .setOnClickListener(this);
+ confHeaderView.findViewById(R.id.conf_enter_or_leave_button)
+ .setOnClickListener(this);
+
+ findViewById(R.id.addCall).setOnClickListener(this);
+ findViewById(R.id.incallHang).setOnClickListener(this);
+
+ findViewById(R.id.incallNumpadShow).setOnClickListener(this);
+
+ List calls = getInitialCalls();
+ setListAdapter(new CalleeListAdapter(calls));
+
+ updateConfState();
+ }
+
+ protected void registerLinphoneListener(boolean register) {
+ if (register)
+ LinphoneManager.getInstance().addListener(this);
+ else
+ LinphoneManager.getInstance().removeListener(this);
+ }
+
+ @Override
+ protected void onResume() {
+ registerLinphoneListener(true);
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ registerLinphoneListener(false);
+ super.onPause();
+ }
+
+ @Override
+ protected Dialog onCreateDialog(final int id) {
+ return new AlertDialog.Builder(this).setView(
+ getLayoutInflater().inflate(R.layout.numpad, null))
+ // .setIcon(R.drawable.logo_linphone_57x57)
+ // .setTitle("Send DTMFs")
+ // .setPositiveButton("hide", new
+ // DialogInterface.OnClickListener() {
+ // public void onClick(DialogInterface dialog, int whichButton)
+ // {
+ // dismissDialog(id);
+ // }
+ // })
+ .create();
+ }
+
+ // protected void conferenceMerge(boolean hostInTheConference, LinphoneCall
+ // ... calls) {
+ // for (LinphoneCall call: calls) {
+ // getLc().addToConference(call, false);
+ // }
+ // getLc().enterConference(hostInTheConference);
+ // }
+
+ // FIXME hack; should have an event?
+ protected final void hackTriggerConfStateUpdate() {
+ updateConfState();
+ }
+
+ private final void updateConfState() {
+ if (lc().getCallsNb() == 0)
+ finish();
+ boolean inConf = lc().isInConference();
+ confHeaderView.setBackgroundColor(inConf ? ACTIVE_BG_COLOR
+ : INACTIVE_BG_COLOR);
+
+ confHeaderView
+ .setVisibility(lc().getConferenceSize() > 0 ? View.VISIBLE
+ : View.GONE);
+
+ TextView v = (TextView) confHeaderView
+ .findViewById(R.id.conf_self_attending);
+ v.setText(inConf ? R.string.in_conf : R.string.out_conf);
+
+ v = (TextView) confHeaderView
+ .findViewById(R.id.conf_enter_or_leave_button);
+ v.setText(inConf ? R.string.in_conf_leave : R.string.out_conf_enter);
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.addCall:
+ Toast.makeText(this,
+ "Should now finish this activity to go back to dialer",
+ Toast.LENGTH_LONG).show();
+ // startActivityForResult(new Intent().setClass(this,
+ // LinphoneContactSelectorActivity.class), 0);
+ break;
+ case R.id.conf_enter_or_leave_button:
+ if (lc().isInConference()) {
+ lc().leaveConference();
+ } else {
+ lc().enterConference();
+ }
+ break;
+ case R.id.terminate_conference:
+ lc().terminateConference();
+ findViewById(R.id.conf_header).setVisibility(View.GONE);
+ break;
+ case R.id.incallHang:
+ lc().terminateAllCalls();
+ finish();
+ break;
+ case R.id.incallNumpadShow:
+ showDialog(numpad_dialog_id);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ private class CalleeListAdapter extends BaseAdapter {
+ private List linphoneCalls;
+
+ public CalleeListAdapter(List calls) {
+ linphoneCalls = calls;
+
+ }
+
+ public int getCount() {
+ return linphoneCalls != null ? linphoneCalls.size() : 0;
+ }
+
+ public Object getItem(int position) {
+ return linphoneCalls.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ private boolean aConferenceIsPossible() {
+ if (lc().getCallsNb() < 2)
+ return false;
+ int count = 0;
+ for (LinphoneCall call : linphoneCalls) {
+ int stateId = call.getState().value();
+ boolean connectionEstablished = stateId == State.ID_STREAMS_RUNNING
+ || stateId == State.ID_PAUSED
+ || stateId == State.ID_PAUSED_BY_REMOTE;
+ if (connectionEstablished)
+ count++;
+ if (count >= 2)
+ return true;
+ }
+ return false;
+ }
+
+ public View getView(int position, View v, ViewGroup parent) {
+ if (v == null) {
+ v = getLayoutInflater().inflate(R.layout.conf_callee, null);
+ }
+
+ LinphoneCall call = linphoneCalls.get(position);
+ int stateId = call.getState().value();
+
+ ((TextView) v.findViewById(R.id.name)).setText(call
+ .getRemoteAddress().getDisplayName());
+ ((TextView) v.findViewById(R.id.address)).setText(call
+ .getRemoteAddress().getUserName());
+
+ boolean isInConference = call.isInConference();
+ boolean currentlyActiveCall = !isInConference
+ && stateId == State.ID_STREAMS_RUNNING;
+ int bgColor = INACTIVE_BG_COLOR;
+ if (stateId == State.ID_INCOMING_RECEIVED) {
+ bgColor = INCOMING_BG_COLOR;
+ } else if (currentlyActiveCall) {
+ bgColor = ACTIVE_BG_COLOR;
+ } else if (isInConference) {
+ bgColor = CONFERENCE_BG_COLOR;
+ }
+ v.setBackgroundColor(bgColor);
+
+ boolean connectionEstablished = stateId == State.ID_STREAMS_RUNNING
+ || stateId == State.ID_PAUSED
+ || stateId == State.ID_PAUSED_BY_REMOTE;
+ View confButton = v.findViewById(R.id.merge_to_conference);
+ boolean showMergeToConf = !isInConference && connectionEstablished
+ && aConferenceIsPossible();
+ confButton
+ .setVisibility(showMergeToConf ? View.VISIBLE : View.GONE);
+
+ View unhookCallButton = v.findViewById(R.id.unhook_call);
+ boolean showUnhook = stateId == State.ID_INCOMING_RECEIVED;
+ unhookCallButton.setVisibility(showUnhook ? View.VISIBLE
+ : View.GONE);
+
+ View terminateCallButton = v.findViewById(R.id.terminate_call);
+ terminateCallButton.setVisibility(!isInConference ? View.VISIBLE
+ : View.GONE);
+
+ View pauseButton = v.findViewById(R.id.pause);
+ boolean showPause = !isInConference
+ && call.getState().equals(State.StreamsRunning);
+ pauseButton.setVisibility(showPause ? View.VISIBLE : View.GONE);
+
+ View resumeButton = v.findViewById(R.id.resume);
+ boolean showResume = !isInConference
+ && call.getState().equals(State.Paused);
+ resumeButton.setVisibility(showResume ? View.VISIBLE : View.GONE);
+
+ v.findViewById(R.id.addVideo).setVisibility(
+ !showUnhook && linphoneCalls.size() == 1 ? View.VISIBLE
+ : View.GONE);
+
+ createAndAttachCallViewClickListener(position, confButton,
+ unhookCallButton, terminateCallButton, pauseButton,
+ resumeButton);
+ return v;
+ }
+
+ private void createAndAttachCallViewClickListener(final int position,
+ final View confButton, final View unhookCallButton,
+ final View terminateCallButton, final View pauseButton,
+ final View resumeButton) {
+ OnClickListener l = new OnClickListener() {
+ public void onClick(View v) {
+ LinphoneCall call = linphoneCalls.get(position);
+ if (v == confButton) {
+ lc().addToConference(call);
+ } else if (v == terminateCallButton) {
+ lc().terminateCall(call);
+ } else if (v == pauseButton) {
+ lc().pauseCall(call);
+ } else if (v == resumeButton) {
+ lc().resumeCall(call);
+ } else if (v == unhookCallButton) {
+ LinphoneCall currentCall = lc().getCurrentCall();
+ if (currentCall != null) lc().pauseCall(currentCall);
+ try {
+ lc().acceptCall(call);
+ } catch (LinphoneCoreException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ };
+ confButton.setOnClickListener(l);
+ terminateCallButton.setOnClickListener(l);
+ pauseButton.setOnClickListener(l);
+ resumeButton.setOnClickListener(l);
+ unhookCallButton.setOnClickListener(l);
+ }
+ }
+
+ private Handler mHandler = new Handler();
+
+ public void onCallStateChanged(final LinphoneCall call, final State state,
+ final String message) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ CalleeListAdapter adapter = (CalleeListAdapter) getListAdapter();
+
+ switch (state.value()) {
+ case State.ID_INCOMING_RECEIVED:
+ case State.ID_OUTGOING_RINGING:
+ adapter.linphoneCalls.add(call);
+ Collections.sort(adapter.linphoneCalls,
+ ConferenceActivity.this);
+ adapter.notifyDataSetInvalidated();
+ break;
+ case State.ID_PAUSED:
+ case State.ID_PAUSED_BY_REMOTE:
+ case State.ID_STREAMS_RUNNING:
+ Collections.sort(adapter.linphoneCalls,
+ ConferenceActivity.this);
+ adapter.notifyDataSetChanged();
+ break;
+ case State.ID_CALL_END:
+ adapter.linphoneCalls.remove(call);
+ Collections.sort(adapter.linphoneCalls,
+ ConferenceActivity.this);
+ adapter.notifyDataSetInvalidated();
+ break;
+ default:
+ break;
+ }
+
+ updateConfState();
+ }
+ });
+ }
+
+ public int compare(LinphoneCall c1, LinphoneCall c2) {
+ if (c1 == c2)
+ return 0;
+
+ boolean inConfC1 = c1.isInConference();
+ boolean inConfC2 = c2.isInConference();
+ if (inConfC1 && !inConfC2)
+ return -1;
+ if (!inConfC1 && inConfC2)
+ return 1;
+
+ int durationDiff = c1.getDuration() - c2.getDuration();
+ return durationDiff;
+
+ }
+ /*
+ * public int compare(LinphoneCall c1, LinphoneCall c2) { if (c1 == c2)
+ * return 0;
+ *
+ * boolean inConfC1 = c1.isInConference(); boolean inConfC2 =
+ * c2.isInConference(); if (inConfC1 && !inConfC2) return -1; if (!inConfC1
+ * && inConfC2) return 1;
+ *
+ * int compUserName =
+ * c1.getRemoteAddress().getUserName().compareToIgnoreCase
+ * (c2.getRemoteAddress().getUserName()); if (inConfC1 && inConfC2) { return
+ * compUserName; }
+ *
+ * // bellow, ringings and incoming int c1State = c1.getState().value(); int
+ * c2State = c2.getState().value();
+ *
+ * boolean c1StateIsEstablishing = c1State == State.ID_INCOMING_RECEIVED ||
+ * c1State == State.ID_OUTGOING_RINGING; boolean c2StateIsEstablishing =
+ * c2State == State.ID_INCOMING_RECEIVED || c2State ==
+ * State.ID_OUTGOING_RINGING;
+ *
+ * // Xor only one establishing state if (c1StateIsEstablishing ^
+ * c2StateIsEstablishing) { // below return !c1StateIsEstablishing ? -1 : 1;
+ * }
+ *
+ * // Xor only one paused state if (c1State == State.ID_PAUSED ^ c2State ==
+ * State.ID_PAUSED) { return c1State == State.ID_PAUSED ? -1 : 1; }
+ *
+ * return compUserName; //Duration() - c1.getDuration(); }
+ */
+}
diff --git a/src/org/linphone/DialerActivity.java b/src/org/linphone/DialerActivity.java
index 3aa7d2cd9..8027d4449 100644
--- a/src/org/linphone/DialerActivity.java
+++ b/src/org/linphone/DialerActivity.java
@@ -21,6 +21,7 @@ package org.linphone;
import org.linphone.LinphoneManager.NewOutgoingCallUiListener;
import org.linphone.LinphoneService.LinphoneGuiListener;
import org.linphone.core.CallDirection;
+import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCore;
import org.linphone.core.Log;
@@ -219,7 +220,8 @@ public class DialerActivity extends LinphoneManagerWaitActivity implements Linph
private void enterIncallMode(LinphoneCore lc) {
- mDisplayNameView.setText(LinphoneManager.getInstance().extractADisplayName());
+ LinphoneAddress address = LinphoneManager.getLc().getRemoteAddress();
+ mDisplayNameView.setText(LinphoneManager.extractADisplayName(getResources(), address));
// setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
@@ -227,8 +229,9 @@ public class DialerActivity extends LinphoneManagerWaitActivity implements Linph
if (!mWakeLock.isHeld()) mWakeLock.acquire();
if (useIncallActivity) {
- LinphoneActivity.instance().startIncallActivity(
- mDisplayNameView.getText(), mAddress.getPictureUri());
+// LinphoneActivity.instance().startIncallActivity(
+// mDisplayNameView.getText(), mAddress.getPictureUri());
+ LinphoneActivity.instance().startConferenceActivity();
} else {
loadMicAndSpeakerUiStateFromManager();
mCallControlRow.setVisibility(View.GONE);
@@ -319,6 +322,8 @@ public class DialerActivity extends LinphoneManagerWaitActivity implements Linph
@Override
protected Dialog onCreateDialog(int id) {
if (id == incomingCallDialogId) {
+ LinphoneAddress address = LinphoneManager.getLc().getRemoteAddress();
+ String from = LinphoneManager.extractIncomingRemoteName(getResources(), address);
View incomingCallView = getLayoutInflater().inflate(R.layout.incoming_call, null);
final Dialog dialog = new AlertDialog.Builder(this)
diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java
index c7e63a0ef..1f5a3b84a 100644
--- a/src/org/linphone/LinphoneActivity.java
+++ b/src/org/linphone/LinphoneActivity.java
@@ -24,6 +24,7 @@ import static android.content.Intent.ACTION_MAIN;
import java.util.List;
import org.linphone.LinphoneManager.EcCalibrationListener;
+import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.Log;
@@ -66,6 +67,7 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
static final int FIRST_LOGIN_ACTIVITY = 101;
static final int INCALL_ACTIVITY = 102;
static final int INCOMING_CALL_ACTIVITY = 103;
+ private static final int conference_activity = 104;
private static final String PREF_CHECK_CONFIG = "pref_check_config";
private static LinphoneActivity instance;
@@ -141,7 +143,7 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
if (savedInstanceState !=null && savedInstanceState.getBoolean(SCREEN_IS_HIDDEN,false)) {
hideScreen(true);
- }
+ }
}
@@ -217,7 +219,8 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
gotToDialer();
} else {
if (getResources().getBoolean(R.bool.use_incall_activity)) {
- startIncallActivity(LinphoneManager.getInstance().extractADisplayName(), null);
+ LinphoneAddress address = LinphoneManager.getLc().getRemoteAddress();
+ startIncallActivity(LinphoneManager.getInstance().extractADisplayName(getResources(), address), null);
} else {
// TODO
Log.e("Not handled case: recreation while in call and not using incall activity");
@@ -478,11 +481,13 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
}
public void startIncallActivity(CharSequence callerName, Uri pictureUri) {
- Intent intent = new Intent().setClass(this, IncallActivity.class)
+/* Intent intent = new Intent().setClass(this, IncallActivity.class)
.putExtra(IncallActivity.CONTACT_KEY, callerName);
if (pictureUri != null)
intent.putExtra(IncallActivity.PICTURE_URI_KEY, pictureUri.toString());
- startActivityForResult(intent, INCALL_ACTIVITY);
+ startActivityForResult(intent, INCALL_ACTIVITY);*/
+ // Hacked
+ startConferenceActivity();
}
public void closeIncallActivity() {
@@ -490,7 +495,6 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
}
public void startVideoActivity() {
-
mHandler.post(new Runnable() {
public void run() {
startActivityForResult(new Intent().setClass(
@@ -501,6 +505,17 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
});
LinphoneManager.getInstance().routeAudioToSpeaker();
}
+
+ public void startConferenceActivity() {
+ mHandler.post(new Runnable() {
+ public void run() {
+ startActivityForResult(new Intent().setClass(
+ LinphoneActivity.this,
+ ConferenceActivity.class),
+ conference_activity);
+ }
+ });
+ }
public void finishVideoActivity() {
mHandler.post(new Runnable() {
@@ -509,4 +524,5 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
}
});
}
+
}
diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java
index 0fa9acef7..ac15fcd08 100644
--- a/src/org/linphone/LinphoneManager.java
+++ b/src/org/linphone/LinphoneManager.java
@@ -39,9 +39,13 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
+import org.linphone.LinphoneSimpleListener.LinphoneServiceListener;
+import org.linphone.core.Hacks;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAuthInfo;
import org.linphone.core.LinphoneCall;
@@ -116,7 +120,17 @@ public final class LinphoneManager implements LinphoneCoreListener {
private String basePath;
private static boolean sExited;
-
+ private List simpleListeners = new ArrayList();
+ public void addListener(LinphoneSimpleListener listener) {
+ if (!simpleListeners.contains(listener)) {
+ simpleListeners.add(listener);
+ }
+ }
+ public void removeListener(LinphoneSimpleListener listener) {
+ simpleListeners.remove(listener);
+ }
+
+
private LinphoneManager(final Context c) {
sExited=false;
basePath = c.getFilesDir().getAbsolutePath();
@@ -203,14 +217,14 @@ public final class LinphoneManager implements LinphoneCoreListener {
}
}
}
-
+
public synchronized static final LinphoneManager createAndStart(
Context c, LinphoneServiceListener listener) {
if (instance != null)
throw new RuntimeException("Linphone Manager is already initialized");
instance = new LinphoneManager(c);
- instance.serviceListener = listener;
+ instance.listenerDispatcher.setServiceListener(listener);
instance.startLibLinphone(c);
if (Version.isVideoCapable())
@@ -245,14 +259,14 @@ public final class LinphoneManager implements LinphoneCoreListener {
String to = address.getText().toString();
if (mLc.isIncall()) {
- serviceListener.tryingNewOutgoingCallButAlreadyInCall();
+ listenerDispatcher.tryingNewOutgoingCallButAlreadyInCall();
return;
}
LinphoneAddress lAddress;
try {
lAddress = mLc.interpretUrl(to);
} catch (LinphoneCoreException e) {
- serviceListener.tryingNewOutgoingCallButWrongDestinationAddress();
+ listenerDispatcher.tryingNewOutgoingCallButWrongDestinationAddress();
return;
}
lAddress.setDisplayName(address.getDisplayedName());
@@ -269,7 +283,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
} catch (LinphoneCoreException e) {
- serviceListener.tryingNewOutgoingCallButCannotGetCallParameters();
+ listenerDispatcher.tryingNewOutgoingCallButCannotGetCallParameters();
return;
}
}
@@ -646,25 +660,11 @@ public final class LinphoneManager implements LinphoneCoreListener {
- public interface LinphoneServiceListener {
- void onGlobalStateChanged(GlobalState state, String message);
- void tryingNewOutgoingCallButCannotGetCallParameters();
- void tryingNewOutgoingCallButWrongDestinationAddress();
- void tryingNewOutgoingCallButAlreadyInCall();
- void onRegistrationStateChanged(RegistrationState state, String message);
- void onCallStateChanged(LinphoneCall call, State state, String message);
- void onRingerPlayerCreated(MediaPlayer mRingerPlayer);
- void onDisplayStatus(String message);
- void onAlreadyInVideoCall();
- void onCallEncryptionChanged(LinphoneCall call, boolean encrypted,
- String authenticationToken);
- }
-
public interface EcCalibrationListener {
void onEcCalibrationStatus(EcCalibratorStatus status, int delayMs);
}
- private LinphoneServiceListener serviceListener;
+ private ListenerDispatcher listenerDispatcher = new ListenerDispatcher(simpleListeners);
private LinphoneCall.State mCurrentCallState;
private MediaPlayer mRingerPlayer;
@@ -689,32 +689,31 @@ public final class LinphoneManager implements LinphoneCoreListener {
public void displayStatus(final LinphoneCore lc, final String message) {
Log.i(message);
lastLcStatusMessage=message;
- serviceListener.onDisplayStatus(message);
+ listenerDispatcher.onDisplayStatus(message);
}
public void globalState(final LinphoneCore lc, final LinphoneCore.GlobalState state, final String message) {
Log.i("new state [",state,"]");
- serviceListener.onGlobalStateChanged(state, message);
+ listenerDispatcher.onGlobalStateChanged(state, message);
}
public void registrationState(final LinphoneCore lc, final LinphoneProxyConfig cfg,final LinphoneCore.RegistrationState state,final String message) {
Log.i("new state ["+state+"]");
- serviceListener.onRegistrationStateChanged(state, message);
+ listenerDispatcher.onRegistrationStateChanged(state, message);
}
public void callState(final LinphoneCore lc,final LinphoneCall call, final State state, final String message) {
Log.i("new state [",state,"]");
if (state == IncomingReceived && !call.equals(lc.getCurrentCall())) {
- if (call.getReplacedCall()==null){
- //no multicall support, just decline
- lc.terminateCall(call);
- }//otherwise it will be accepted automatically.
-
- return;
+ if (call.getReplacedCall()!=null){
+ // attended transfer
+ // it will be accepted automatically.
+ return;
+ }
}
if (state == IncomingReceived) {
@@ -746,12 +745,12 @@ public final class LinphoneManager implements LinphoneCoreListener {
}
mCurrentCallState=state;
- serviceListener.onCallStateChanged(call, state, message);
+ listenerDispatcher.onCallStateChanged(call, state, message);
}
public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,
boolean encrypted, String authenticationToken) {
- serviceListener.onCallEncryptionChanged(call, encrypted, authenticationToken);
+ listenerDispatcher.onCallEncryptionChanged(call, encrypted, authenticationToken);
}
public void ecCalibrationStatus(final LinphoneCore lc,final EcCalibratorStatus status, final int delayMs,
@@ -793,7 +792,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
if (mRingerPlayer == null) {
mRingerPlayer = new MediaPlayer();
mRingerPlayer.setAudioStreamType(STREAM_RING);
- serviceListener.onRingerPlayerCreated(mRingerPlayer);
+ listenerDispatcher.onRingerPlayerCreated(mRingerPlayer);
mRingerPlayer.prepare();
mRingerPlayer.setLooping(true);
mRingerPlayer.start();
@@ -820,21 +819,20 @@ public final class LinphoneManager implements LinphoneCoreListener {
}
- public String extractADisplayName() {
- final LinphoneAddress remote = mLc.getRemoteAddress();
- if (remote == null) return mR.getString(R.string.unknown_incoming_call_name);
+ public static String extractADisplayName(Resources r, LinphoneAddress address) {
+ if (address == null) return r.getString(R.string.unknown_incoming_call_name);
- final String displayName = remote.getDisplayName();
+ final String displayName = address.getDisplayName();
if (displayName!=null) {
return displayName;
- } else if (remote.getUserName() != null){
- return remote.getUserName();
+ } else if (address.getUserName() != null){
+ return address.getUserName();
} else {
- String rms = remote.toString();
+ String rms = address.toString();
if (rms != null && rms.length() > 1)
return rms;
- return mR.getString(R.string.unknown_incoming_call_name);
+ return r.getString(R.string.unknown_incoming_call_name);
}
}
@@ -887,7 +885,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
public void addVideo() {
if (!LinphoneManager.getLc().isIncall()) return;
if (!reinviteWithVideo()) {
- serviceListener.onAlreadyInVideoCall();
+ listenerDispatcher.onAlreadyInVideoCall();
}
}
@@ -902,15 +900,14 @@ public final class LinphoneManager implements LinphoneCoreListener {
return false;
}
- public String extractIncomingRemoteName() {
- if (!mR.getBoolean(R.bool.show_full_remote_address_on_incoming_call))
- return extractADisplayName();
+ public static String extractIncomingRemoteName(Resources r, LinphoneAddress linphoneAddress) {
+ if (!r.getBoolean(R.bool.show_full_remote_address_on_incoming_call))
+ return extractADisplayName(r, linphoneAddress);
- LinphoneAddress remote = mLc.getRemoteAddress();
- if (remote != null)
- return remote.toString();
+ if (linphoneAddress != null)
+ return linphoneAddress.toString();
- return mR.getString(R.string.unknown_incoming_call_name);
+ return r.getString(R.string.unknown_incoming_call_name);
}
public void adjustSoftwareVolume(int i) {
@@ -948,4 +945,71 @@ public final class LinphoneManager implements LinphoneCoreListener {
return getLc();
}
+ private static class ListenerDispatcher implements LinphoneServiceListener {
+ private LinphoneServiceListener serviceListener;
+ List simpleListeners;
+ public ListenerDispatcher(List simpleListeners) {
+ this.simpleListeners = simpleListeners;
+ }
+
+ @SuppressWarnings("unchecked")
+ private List getSimpleListeners(Class clazz) {
+ List list = new ArrayList();
+ for (LinphoneSimpleListener l : simpleListeners) {
+ if (clazz.isInstance(l)) list.add((T) l);
+ }
+ return list;
+ }
+
+ public void setServiceListener(LinphoneServiceListener s) {
+ this.serviceListener = s;
+ }
+
+ public void onAlreadyInVideoCall() {
+ if (serviceListener != null) serviceListener.onAlreadyInVideoCall();
+ }
+
+ public void onCallEncryptionChanged(LinphoneCall call,
+ boolean encrypted, String authenticationToken) {
+ if (serviceListener != null) serviceListener.onCallEncryptionChanged(call, encrypted, authenticationToken);
+ }
+
+ public void onCallStateChanged(LinphoneCall call, State state,
+ String message) {
+ if (serviceListener != null) serviceListener.onCallStateChanged(call, state, message);
+ for (LinphoneOnCallStateChangedListener l : getSimpleListeners(LinphoneOnCallStateChangedListener.class)) {
+ l.onCallStateChanged(call, state, message);
+ }
+ }
+
+ public void onDisplayStatus(String message) {
+ if (serviceListener != null) serviceListener.onDisplayStatus(message);
+ }
+
+ public void onGlobalStateChanged(GlobalState state, String message) {
+ if (serviceListener != null) serviceListener.onGlobalStateChanged( state, message);
+ }
+
+ public void onRegistrationStateChanged(RegistrationState state,
+ String message) {
+ if (serviceListener != null) serviceListener.onRegistrationStateChanged(state, message);
+ }
+
+ public void onRingerPlayerCreated(MediaPlayer mRingerPlayer) {
+ if (serviceListener != null) serviceListener.onRingerPlayerCreated(mRingerPlayer);
+ }
+
+ public void tryingNewOutgoingCallButAlreadyInCall() {
+ if (serviceListener != null) serviceListener.tryingNewOutgoingCallButAlreadyInCall();
+ }
+
+ public void tryingNewOutgoingCallButCannotGetCallParameters() {
+ if (serviceListener != null) serviceListener.tryingNewOutgoingCallButCannotGetCallParameters();
+ }
+
+ public void tryingNewOutgoingCallButWrongDestinationAddress() {
+ if (serviceListener != null) serviceListener.tryingNewOutgoingCallButWrongDestinationAddress();
+ }
+
+ }
}
diff --git a/src/org/linphone/LinphoneService.java b/src/org/linphone/LinphoneService.java
index b06b66025..4e0b1c9e8 100644
--- a/src/org/linphone/LinphoneService.java
+++ b/src/org/linphone/LinphoneService.java
@@ -20,8 +20,9 @@ package org.linphone;
import java.io.IOException;
-import org.linphone.LinphoneManager.LinphoneServiceListener;
import org.linphone.LinphoneManager.NewOutgoingCallUiListener;
+import org.linphone.LinphoneSimpleListener.LinphoneServiceListener;
+import org.linphone.core.Hacks;
import org.linphone.core.LinphoneCall;
import org.linphone.core.Log;
import org.linphone.core.OnlineStatus;
diff --git a/src/org/linphone/LinphoneSimpleListener.java b/src/org/linphone/LinphoneSimpleListener.java
new file mode 100644
index 000000000..d64b2bb3b
--- /dev/null
+++ b/src/org/linphone/LinphoneSimpleListener.java
@@ -0,0 +1,50 @@
+/*
+LinphoneServiceListener.java
+Copyright (C) 2011 Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+package org.linphone;
+
+import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCall.State;
+import org.linphone.core.LinphoneCore.GlobalState;
+import org.linphone.core.LinphoneCore.RegistrationState;
+
+import android.media.MediaPlayer;
+
+public interface LinphoneSimpleListener {
+
+ public static interface LinphoneServiceListener
+ extends LinphoneOnGlobalStateChangedListener, LinphoneOnCallStateChangedListener {
+ void tryingNewOutgoingCallButCannotGetCallParameters();
+ void tryingNewOutgoingCallButWrongDestinationAddress();
+ void tryingNewOutgoingCallButAlreadyInCall();
+ void onRegistrationStateChanged(RegistrationState state, String message);
+ void onRingerPlayerCreated(MediaPlayer mRingerPlayer);
+ void onDisplayStatus(String message);
+ void onAlreadyInVideoCall();
+ void onCallEncryptionChanged(LinphoneCall call, boolean encrypted, String authenticationToken);
+
+ }
+
+ public static interface LinphoneOnGlobalStateChangedListener extends LinphoneSimpleListener {
+ void onGlobalStateChanged(GlobalState state, String message);
+ }
+
+ public static interface LinphoneOnCallStateChangedListener extends LinphoneSimpleListener {
+ void onCallStateChanged(LinphoneCall call, State state, String message);
+ }
+}
diff --git a/src/org/linphone/core/LinphoneCallImpl.java b/src/org/linphone/core/LinphoneCallImpl.java
index 70968e79d..acad5a09f 100644
--- a/src/org/linphone/core/LinphoneCallImpl.java
+++ b/src/org/linphone/core/LinphoneCallImpl.java
@@ -123,8 +123,9 @@ class LinphoneCallImpl implements LinphoneCall {
public boolean areStreamsEncrypted() {
return areStreamsEncrypted(nativePtr);
}
+
public boolean isInConference() {
- // TODO Auto-generated method stub
- return false;
+ LinphoneCallParamsImpl params = new LinphoneCallParamsImpl(getCurrentParamsCopy(nativePtr));
+ return params.localConferenceMode();
}
}
diff --git a/src/org/linphone/core/LinphoneCallParamsImpl.java b/src/org/linphone/core/LinphoneCallParamsImpl.java
index ef05eb228..d9c490ae1 100644
--- a/src/org/linphone/core/LinphoneCallParamsImpl.java
+++ b/src/org/linphone/core/LinphoneCallParamsImpl.java
@@ -48,4 +48,9 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams {
public void setAudioBandwidth(int value) {
audioBandwidth(nativePtr, value);
}
+
+ private native boolean localConferenceMode(long nativePtr);
+ public boolean localConferenceMode() {
+ return localConferenceMode(nativePtr);
+ }
}
diff --git a/src/org/linphone/core/LinphoneCoreImpl.java b/src/org/linphone/core/LinphoneCoreImpl.java
index 92eb4a43c..ab87a17b2 100644
--- a/src/org/linphone/core/LinphoneCoreImpl.java
+++ b/src/org/linphone/core/LinphoneCoreImpl.java
@@ -20,6 +20,7 @@ package org.linphone.core;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
@@ -488,50 +489,68 @@ class LinphoneCoreImpl implements LinphoneCore {
public int getVideoDevice() {
return getVideoDevice(nativePtr);
}
- public void addAllToConference() {
- // TODO Auto-generated method stub
-
- }
- public void addToConference(LinphoneCall call) {
- // TODO Auto-generated method stub
-
- }
- public void enterConference() {
- // TODO Auto-generated method stub
-
- }
- public List getCalls() {
- // TODO Auto-generated method stub
- return null;
- }
- public int getCallsNb() {
- // TODO Auto-generated method stub
- return 0;
- }
- public int getConferenceSize() {
- // TODO Auto-generated method stub
- return 0;
- }
- public boolean isInConference() {
- // TODO Auto-generated method stub
- return false;
- }
+
+
+ private native void leaveConference(long nativePtr);
public void leaveConference() {
- // TODO Auto-generated method stub
-
+ leaveConference(nativePtr);
}
- public void removeFromConference(LinphoneCall call) {
- // TODO Auto-generated method stub
-
+
+ private native void enterConference(long nativePtr);
+ public void enterConference() {
+ enterConference(nativePtr);
}
- public void terminateAllCalls() {
- // TODO Auto-generated method stub
-
+
+ private native boolean isInConference(long nativePtr);
+ public boolean isInConference() {
+ return isInConference(nativePtr);
}
+
+ private native void addToConference(long nativePtr, long nativePtrLcall);
+ public void addToConference(LinphoneCall call, boolean addOthersToNewConference) {
+ addToConference(nativePtr, ((LinphoneCallImpl)call).nativePtr);
+ }
+
+ private native void terminateConference(long nativePtr);
public void terminateConference() {
- // TODO Auto-generated method stub
+ terminateConference(nativePtr);
+ }
+ private native int getConferenceSize(long nativePtr);
+ public int getConferenceSize() {
+ return getConferenceSize(nativePtr);
+ }
+ private native int getCallsNb(long nativePtr);
+ public int getCallsNb() {
+ return getCallsNb(nativePtr);
+ }
+ private native void terminateAllCalls(long nativePtr);
+ public void terminateAllCalls() {
+ terminateAllCalls(nativePtr);
+ }
+ private native long getCall(long nativePtr, int position);
+ @SuppressWarnings("unchecked") public List getCalls() {
+ int size = getCallsNb(nativePtr);
+ List calls = new ArrayList(size);
+ for (int i=0; i < size; i++) {
+ calls.add(new LinphoneCallImpl(getCall(nativePtr, i)));
+ }
+ return calls;
+ }
+ private native void addAllToConference(long nativePtr);
+ public void addAllToConference() {
+ addAllToConference(nativePtr);
}
+ private native void addToConference(long nativePtr);
+ public void addToConference(LinphoneCall call) {
+ addToConference(nativePtr);
+
+ }
+ private native void removeFromConference(long nativePtr);
+ public void removeFromConference(LinphoneCall call) {
+ removeFromConference(nativePtr);
+ }
+
public void transferCall(LinphoneCall call, String referTo) {
// TODO Auto-generated method stub
diff --git a/test/org/linphone/TestConferenceActivity.java b/test/org/linphone/TestConferenceActivity.java
new file mode 100644
index 000000000..212cdaf71
--- /dev/null
+++ b/test/org/linphone/TestConferenceActivity.java
@@ -0,0 +1,350 @@
+/*
+TestIncallCalleeBoxes.java
+Copyright (C) 2011 Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+package org.linphone;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.linphone.core.CallDirection;
+import org.linphone.core.LinphoneAddress;
+import org.linphone.core.LinphoneAuthInfo;
+import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCallLog;
+import org.linphone.core.LinphoneCallParams;
+import org.linphone.core.LinphoneChatRoom;
+import org.linphone.core.LinphoneCore;
+import org.linphone.core.LinphoneCoreException;
+import org.linphone.core.LinphoneFriend;
+import org.linphone.core.LinphoneProxyConfig;
+import org.linphone.core.OnlineStatus;
+import org.linphone.core.PayloadType;
+import org.linphone.core.VideoSize;
+import org.linphone.core.LinphoneCall.State;
+
+import android.os.Bundle;
+import android.os.Handler;
+
+/**
+ * @author Guillaume Beraudo
+ */
+public class TestConferenceActivity extends ConferenceActivity {
+
+ private Handler mHandler = new Handler();
+ private LinphoneCoreTest mTestLc;
+ protected final LinphoneCore lc() {return mTestLc;}
+
+ private void simulateCallAccepted(final LinphoneCall call, int millis) {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ lc().pauseAllCalls();
+ ((LinphoneCallTest)call).state = State.StreamsRunning;
+ onCallStateChanged(call, call.getState(), "simulated out call answered");
+ }
+ }, millis);
+ }
+
+ protected final List getInitialCalls() {
+ List calls = new ArrayList();
+ int duration=0;
+ mTestLc = new LinphoneCoreTest(calls);
+ calls.add(new LinphoneCallTest(duration++, "Tartampion", "06.25.45.98.54", State.StreamsRunning));
+ calls.add(new LinphoneCallTest(duration++, "Durand", "durand@sip.linphone.org", State.StreamsRunning));
+ // calls.add(new LinphoneCallTest(duration++, "Poupoux", "01.58.68.75.32", State.StreamsRunning));
+ calls.add(new LinphoneCallTest(duration++, "Tante Germaine", "+33 1.58.68.75.32", State.Paused));
+ // calls.add(new LinphoneCallTest(duration++, "M. Le président ", "3615 Elysée", State.Paused));
+ calls.add(new LinphoneCallTest(duration++, "01.58.68.75.32", "01.58.68.75.32", State.StreamsRunning));
+ calls.add(new LinphoneCallTest(duration++, "A ringing out guy", "out-ringing@sip.linphone.org", State.OutgoingRinging));
+ calls.add(new LinphoneCallTest(duration++, "A calling in guy", "in@sip.linphone.org", State.IncomingReceived));
+
+ ((LinphoneCallTest)calls.get(0)).inConf=true;
+ ((LinphoneCallTest)calls.get(1)).inConf=true;
+
+ simulateCallAccepted(calls.get(4), 5000);
+ Collections.sort(calls, this);
+
+ mTestLc = new LinphoneCoreTest(calls);
+ return calls;
+ }
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ //if (!serviceStarted) startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
+
+ }
+
+
+
+
+ private class LinphoneCoreTest implements LinphoneCore {
+ List calls;
+ public LinphoneCoreTest(List calls) {
+ this.calls = new ArrayList(calls);
+ //don't keep only the list reference (concurrent access in onStateChanged).
+ }
+ public void acceptCall(LinphoneCall call) throws LinphoneCoreException {
+ if (isInConference()) {
+ leaveConference();
+ } else {
+ pauseCall(getCurrentCall());
+ }
+ changeState(call, State.StreamsRunning);
+ }
+ public void addAuthInfo(LinphoneAuthInfo info) {}
+ public void addFriend(LinphoneFriend lf) throws LinphoneCoreException {}
+ public void addProxyConfig(LinphoneProxyConfig p) throws LinphoneCoreException {}
+ public void adjustSoftwareVolume(int i) {}
+ public void clearAuthInfos() {}
+ public void clearCallLogs() {}
+ public void clearProxyConfigs() {}
+ public LinphoneChatRoom createChatRoom(String to) {return null;}
+ public LinphoneCallParams createDefaultCallParameters() {return null;}
+ public void destroy() {}
+ public void enableEchoCancellation(boolean enable) {}
+ public void enableEchoLimiter(boolean val) {}
+ public void enableIpv6(boolean enable) {}
+ public void enableKeepAlive(boolean enable) {}
+ public void enablePayloadType(PayloadType pt, boolean e)throws LinphoneCoreException {}
+ public void enableSpeaker(boolean value) {}
+ public void enableVideo(boolean vcapEnabled, boolean displayEnabled) {}
+ public PayloadType findPayloadType(String mime, int clockRate) {return null;}
+ public PayloadType[] getAudioCodecs() {return null;}
+ @SuppressWarnings("unchecked")
+ public List getCallLogs() {return null;}
+ public LinphoneCall getCurrentCall() {
+ LinphoneCall active = null;
+ for (LinphoneCall call : calls) {
+ if (call.isInConference() || !call.getState().equals(State.StreamsRunning)) continue;
+ if (active != null) throw new RuntimeException("There are several active calls!");
+ active = call;
+ }
+ return active;
+ }
+ public LinphoneProxyConfig getDefaultProxyConfig() {return null;}
+ public FirewallPolicy getFirewallPolicy() {return null;}
+ public int getPlayLevel() {return 0;}
+ public float getPlaybackGain() {return 0;}
+ public VideoSize getPreferredVideoSize() {return null;}
+ public LinphoneAddress getRemoteAddress() {return null;}
+ public String getRing() {return null;}
+ public Transports getSignalingTransportPorts() {return null;}
+ public String getStunServer() {return null;}
+ public PayloadType[] getVideoCodecs() {return null;}
+ public LinphoneAddress interpretUrl(String d)throws LinphoneCoreException {return null;}
+ public LinphoneCall invite(String d) throws LinphoneCoreException {return null;}
+ public LinphoneCall invite(LinphoneAddress to)throws LinphoneCoreException {return null;}
+ public LinphoneCall inviteAddressWithParams(LinphoneAddress d, LinphoneCallParams p)
+ throws LinphoneCoreException {return null;}
+ public boolean isEchoCancellationEnabled() {return false;}
+ public boolean isInComingInvitePending() {return false;}
+ public boolean isIncall() {return false;}
+ public boolean isKeepAliveEnabled() {return false;}
+ public boolean isMicMuted() {return false;}
+ public boolean isNetworkReachable() {return false;}
+ public boolean isSpeakerEnabled() {return false;}
+ public boolean isVideoEnabled() {return false;}
+ public void iterate() {}
+ public void muteMic(boolean isMuted) {}
+ public boolean pauseAllCalls() {
+ // FIXME may not be right
+ for (LinphoneCall call : calls) {
+ if (!call.isInConference()) {
+ if (call.getState().equals(State.StreamsRunning) || call.getState().equals(State.PausedByRemote))
+ pauseCall(call);
+ }
+ }
+ return false;
+ }
+ public boolean pauseCall(LinphoneCall call) {
+ changeState(call, State.Paused);
+ return true;
+ }
+ public void playDtmf(char number, int duration) {}
+ public boolean resumeCall(LinphoneCall call) {
+ pauseAllCalls();
+ changeState(call, State.StreamsRunning);
+ return true;
+ }
+ public void sendDtmf(char number) {}
+ public void setDefaultProxyConfig(LinphoneProxyConfig proxyCfg) {}
+ public void setDownloadBandwidth(int bw) {}
+ public void setDownloadPtime(int ptime) {}
+ public void setFirewallPolicy(FirewallPolicy pol) {}
+ public void setNetworkReachable(boolean isReachable) {}
+ public void setPlayLevel(int level) {}
+ public void setPlaybackGain(float gain) {}
+ public void setPreferredVideoSize(VideoSize vSize) {}
+ public void setPresenceInfo(int m, String a, OnlineStatus s) {}
+ public void setPreviewWindow(Object w) {}
+ public void setRing(String path) {}
+ public void setRootCA(String path) {}
+ public void setSignalingTransportPorts(Transports transports) {}
+ public void setStunServer(String stunServer) {}
+ public void setUploadBandwidth(int bw) {}
+ public void setUploadPtime(int ptime) {}
+ public void setVideoWindow(Object w) {}
+ public void setZrtpSecretsCache(String file) {}
+ public void startEchoCalibration(Object d)throws LinphoneCoreException {}
+ public void stopDtmf() {}
+ public void terminateCall(LinphoneCall call) {
+ changeStateInConf(call, false);
+ changeState(call, State.CallEnd);
+ }
+ public int updateCall(LinphoneCall call, LinphoneCallParams params) {return 0;}
+ private boolean partOfConf;
+ public void enterConference() {
+ pauseAllCalls();
+ partOfConf=true;
+ hackTriggerConfStateUpdate(); // FIXME hack; should have an event?
+ }
+ public void leaveConference() {
+ partOfConf=false;
+ hackTriggerConfStateUpdate(); // FIXME hack; should have an event?
+ }
+ public boolean isInConference() {return partOfConf;}
+ public int getConferenceSize() {
+ int count=0;
+ for (LinphoneCall c : calls) {
+ if (c.isInConference()) count++;
+ }
+ return count;
+ }
+ public void addAllToConference() {
+ for (LinphoneCall c : calls) {
+ int stateId = c.getState().value();
+ boolean connectionEstablished = stateId == State.ID_STREAMS_RUNNING || stateId == State.ID_PAUSED || stateId == State.ID_PAUSED_BY_REMOTE;
+ if (connectionEstablished) changeStateInConf(c, true);
+ }
+ enterConference();
+ }
+ public void addToConference(LinphoneCall call) {
+ if (getConferenceSize() == 0) {
+ addAllToConference();
+ } else {
+ boolean mergingActiveCall = call.equals(getCurrentCall());
+ changeStateInConf(call, true);
+ if (mergingActiveCall) enterConference();
+ }
+ }
+ public void terminateConference() {
+ leaveConference();
+ for (LinphoneCall call : calls) {
+ if (!call.isInConference()) continue;
+ terminateCall(call);
+ }
+ }
+ private void changeState(LinphoneCall call, State state) {
+ ((LinphoneCallTest)call).state=state;
+ onCallStateChanged(call, state, "triggered by stub");
+ }
+ private void changeStateInConf(LinphoneCall call, boolean inConf) {
+ ((LinphoneCallTest)call).inConf=inConf;
+ onCallStateChanged(call, call.getState(), "in conf state changed");
+ }
+ public int getCallsNb() {
+ int count=0;
+ for (LinphoneCall call : calls) {
+ if (!State.CallEnd.equals(call.getState())) count++;
+ }
+ return count;
+ }
+ public void terminateAllCalls() {
+ terminateConference();
+ for(LinphoneCall call : calls) {
+ if (!State.CallEnd.equals(call.getState())) terminateCall(call);
+ }
+ }
+ @SuppressWarnings("unchecked")
+ public List getCalls() {
+ return new ArrayList(calls);
+ }
+ public void removeFromConference(LinphoneCall call) {
+ changeState(call, State.StreamsRunning);
+ }
+
+ }
+
+
+ private static class LinphoneAddressTest implements LinphoneAddress {
+ private String displayName;
+ private String number;
+ public LinphoneAddressTest(String niceName, String number) {
+ this.displayName = niceName;
+ this.number = number;}
+ public String asString() {return displayName;}
+ public String asStringUriOnly() {return null;}
+ public String getDisplayName() {return displayName;}
+ public String getDomain() {return "example.org";}
+ public String getPort() {return "5060";}
+ public int getPortInt() {return 5060;}
+ public String getUserName() {return number;}
+ public void setDisplayName(String name) {}
+ public void setDomain(String domain) {}
+ public void setPort(String port) {}
+ public void setPortInt(int port) {}
+ public void setUserName(String username) {}
+ public void clean() {}
+ @Override public String toString() {return displayName;}
+ }
+
+
+
+ private static class LinphoneCallTest implements LinphoneCall {
+ private boolean inConf;
+ private State state;
+ private LinphoneAddress remoteAddress;
+ private int duration;
+
+ public LinphoneCallTest(int duration, String name, String number, State state) {
+ this.duration = duration;
+ this.state = state;
+ remoteAddress = new LinphoneAddressTest(name, number);
+ }
+
+ public boolean areStreamsEncrypted() {return false;}
+ public void enableCamera(boolean enabled) {}
+ public void enableEchoCancellation(boolean enable) {}
+ public void enableEchoLimiter(boolean enable) {}
+ public String getAuthenticationToken() {return null;}
+ public float getAverageQuality() {return 0;}
+ public LinphoneCallLog getCallLog() {return null;}
+ public LinphoneCallParams getCurrentParamsCopy() {return null;}
+ public float getCurrentQuality() {return 0;}
+ public CallDirection getDirection() {return null;}
+ public int getDuration() {return duration;}
+ public LinphoneAddress getRemoteAddress() {return remoteAddress;}
+ public LinphoneCall getReplacedCall() {return null;}
+ public State getState() {return state;}
+ public boolean isAuthenticationTokenVerified() {return false;}
+ public boolean isEchoCancellationEnabled() {return false;}
+ public boolean isEchoLimiterEnabled() {return false;}
+ public boolean isInConference() { return inConf;}
+ }
+
+
+ @Override
+ protected void registerLinphoneListener(boolean register) {
+ // Do nothing (especially, don't call LinphoneManager!)
+ }
+}
+
+