Preliminary code for conferencing support.

This commit is contained in:
Guillaume Beraudo 2011-09-14 11:04:14 +02:00
parent a29056b1e2
commit 8ffc8319fe
25 changed files with 1146 additions and 103 deletions

View file

@ -6,6 +6,7 @@
<classpathentry kind="src" path="submodules/linphone/java/common"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="src" path="submodules/linphone/coreapi/help/java"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -42,7 +42,13 @@
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity android:name="org.linphone.ConferenceActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity android:name="org.linphone.IncallActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
@ -103,6 +109,15 @@
<activity android:name="org.linphone.TestConferenceActivity"
android:label="Test Linphone conference UI"
android:theme="@android:style/Theme.NoTitleBar"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="org.linphone.core.tutorials.TestVideoActivity"
android:label="Video test"
android:theme="@android:style/Theme.NoTitleBar"

BIN
res/drawable/conf_merge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,011 B

BIN
res/drawable/conf_pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,007 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
res/drawable/conf_video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent" >
<ImageView android:id="@+id/picture" android:layout_width="wrap_content" android:src="@drawable/unknown_person" android:layout_height="wrap_content"
android:layout_alignParentLeft="true"/>
<LinearLayout android:id="@+id/callee_buttons" android:layout_alignParentRight="true"
android:layout_width="wrap_content" android:layout_height="wrap_content">
<ImageButton android:id="@+id/addVideo" android:src="@drawable/conf_video"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ImageButton android:id="@+id/merge_to_conference" android:src="@drawable/conf_merge"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ImageButton android:id="@+id/unhook_call" android:src="@drawable/conf_unhook"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ImageButton android:id="@+id/terminate_call" android:src="@drawable/conf_terminate"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ImageButton android:id="@+id/pause" android:src="@drawable/conf_pause"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<ImageButton android:id="@+id/resume" android:src="@drawable/conf_resume"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"
android:layout_toLeftOf="@id/callee_buttons" android:layout_toRightOf="@id/picture">
<TextView android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content" />
<TextView android:id="@+id/address" android:layout_width="fill_parent" android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<RelativeLayout android:id="@+id/conf_header"
android:layout_width="fill_parent" android:layout_height="wrap_content" >
<LinearLayout android:id="@+id/conf_management_buttons" android:layout_alignParentRight="true"
android:layout_width="wrap_content" android:layout_height="wrap_content">
<Button android:id="@+id/conf_enter_or_leave_button" android:layout_alignParentRight="true"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<ImageButton android:id="@+id/terminate_conference" android:src="@drawable/conf_terminate"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"
android:layout_toLeftOf="@id/conf_management_buttons" android:layout_alignParentLeft="true">
<TextView android:text="@string/conf_text_you_host_a_conference"
android:layout_width="fill_parent" android:layout_height="wrap_content" />
<TextView android:id="@+id/conf_self_attending"
android:layout_width="fill_parent" android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
<LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content">
<ToggleButton android:textOn="Mute" android:textOff="Mute" android:id="@+id/toggleMuteMic"
android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" />
<ToggleButton android:textOn="Speaker" android:textOff="Speaker" android:id="@+id/toggleSpeaker"
android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" />
<ToggleButton android:textOn="Bluetooth" android:textOff="Bluetooth" android:id="@+id/toggleBluetooth"
android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" />
</LinearLayout>
<!--android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1-->
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content">
<Button android:text="+ Add call" android:id="@+id/addCall"
android:layout_width="wrap_content" android:layout_height="wrap_content"
/>
<org.linphone.ui.HangCallButton android:id="@+id/incallHang" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/mini_stopcall_red" android:layout_weight="1" />
<Button android:id="@+id/incallNumpadShow" android:text="@string/show_send_dtmfs_button"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>

View file

@ -24,9 +24,7 @@
</TableRow>
<TableRow>
<org.linphone.ui.AddVideoButton android:id="@+id/AddVideo" android:src="@drawable/startvideo_green"
android:layout_height="wrap_content" android:layout_width="wrap_content" android:height="10px"
android:layout_column="1" />
</TableRow>
</TableLayout>
@ -34,8 +32,21 @@
</FrameLayout>
<View android:layout_weight="1" android:layout_width="0px" android:layout_height="0px" android:visibility="invisible"/>
<LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content">
<Button android:text="+ Add call" android:id="@+id/toggleButton4" android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/>
<Button android:text="Video" android:id="@+id/toggleButton4" android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/>
<Button android:text="Chat" android:id="@+id/toggleButton4" android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/>
</LinearLayout>
<LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content">
<ToggleButton android:text="Mute" android:id="@+id/toggleButton1" android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"></ToggleButton>
<ToggleButton android:text="Speaker" android:id="@+id/toggleButton2" android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"></ToggleButton>
<ToggleButton android:text="Bluetooth" android:id="@+id/toggleButton3" android:width="0px" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"></ToggleButton>
</LinearLayout>
<!-- <org.linphone.ui.AddVideoButton android:id="@+id/AddVideo" android:src="@drawable/startvideo_green"-->
<!-- android:layout_height="wrap_content" android:layout_width="fill_parent" android:width="0px" android:layout_weight="1"/>-->
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content">
<org.linphone.ui.HangCallButton android:id="@+id/incallHang" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/stopcall_red" android:background="@drawable/clavier_bg" android:layout_weight="10" />

View file

@ -10,7 +10,7 @@
<bool name="useFirstLoginActivity">false</bool>
<bool name="useMenuSettings">true</bool>
<bool name="useMenuAbout">true</bool>
<bool name="use_incall_activity">false</bool>
<bool name="use_incall_activity">true</bool>
<bool name="use_video_activity">true</bool>
<bool name="show_full_remote_address_on_incoming_call">true</bool>

View file

@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="show_send_dtmfs_button">DTMFs</string>
<string name="conf_text_you_host_a_conference">You host a conference</string>
<string name="in_conf">You are part of it</string>
<string name="in_conf_leave">Go out</string>
<string name="out_conf">You are out of it</string>
<string name="out_conf_enter">Go in</string>
<string name="pref_audio_hacks_title">Audio hacks</string>
<string name="pref_audio_use_specific_mode_title">Use specific mode hack</string>
<string name="pref_audio_use_specific_mode_summary">0=MODE_NORMAL (default), 2=MODE_IN_CALL</string>

View file

@ -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<LinphoneCall>,
OnClickListener {
private View confHeaderView;
// Start Override to test block
protected LinphoneCore lc() {
return LinphoneManager.getLc();
}
@SuppressWarnings("unchecked")
protected List<LinphoneCall> 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<LinphoneCall> 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<LinphoneCall> linphoneCalls;
public CalleeListAdapter(List<LinphoneCall> 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(); }
*/
}

View file

@ -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)

View file

@ -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
}
});
}
}

View file

@ -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<LinphoneSimpleListener> simpleListeners = new ArrayList<LinphoneSimpleListener>();
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<LinphoneSimpleListener> simpleListeners;
public ListenerDispatcher(List<LinphoneSimpleListener> simpleListeners) {
this.simpleListeners = simpleListeners;
}
@SuppressWarnings("unchecked")
private <T> List<T> getSimpleListeners(Class<T> clazz) {
List<T> list = new ArrayList<T>();
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();
}
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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<LinphoneCall> calls = new ArrayList<LinphoneCall>(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

View file

@ -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<LinphoneCall> getInitialCalls() {
List<LinphoneCall> calls = new ArrayList<LinphoneCall>();
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<LinphoneCall> calls;
public LinphoneCoreTest(List<LinphoneCall> calls) {
this.calls = new ArrayList<LinphoneCall>(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<LinphoneCall>(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!)
}
}