Initial support for conferencing.

This commit is contained in:
Guillaume Beraudo 2011-09-20 14:36:15 +02:00
parent 84ed7ab7fd
commit 70a52abf30
33 changed files with 791 additions and 236 deletions

View file

@ -110,9 +110,9 @@
<activity android:name="org.linphone.TestConferenceActivity" <activity android:name="org.linphone.TestConferenceActivity"
android:label="Test Linphone conference UI" android:label="Conf test"
android:theme="@android:style/Theme.NoTitleBar" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:enabled="true"> android:enabled="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
<solid android:color="@color/conf_active_bg_color"/>
<corners android:radius="15dp" />
</shape>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#777777"/>
<corners android:radius="15dp"/>
</shape>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
<solid android:color="#336600"/>
<corners android:radius="15dp" />
</shape>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
<solid android:color="#444444"/>
<corners android:radius="15dp" />
</shape>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#2E64FE"/>
<corners android:radius="15dp"/>
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
</shape>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#ff9200"/>
<corners android:radius="15dp"/>
</shape>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/conf_callee_pressed_bg" />
<item android:drawable="@drawable/conf_callee_active_bg" />
</selector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/conf_callee_pressed_bg" />
<item android:drawable="@drawable/conf_callee_incoming_bg" />
</selector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/conf_callee_pressed_bg" />
<item android:drawable="@drawable/conf_callee_inconf_bg" />
</selector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/conf_callee_pressed_bg" />
<item android:drawable="@drawable/conf_callee_bg" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -51,6 +51,15 @@
<org.linphone.ui.HangCallButton android:id="@+id/HangUp" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:src="@drawable/stopcall_red" android:background="@drawable/clavier_bg"/> <org.linphone.ui.HangCallButton android:id="@+id/HangUp" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:src="@drawable/stopcall_red" android:background="@drawable/clavier_bg"/>
</LinearLayout> </LinearLayout>
<LinearLayout android:id="@+id/AddCallControlRow" android:layout_height="wrap_content" android:layout_width="fill_parent" android:gravity="bottom" android:visibility="gone">
<Button android:id="@+id/AddCallButton" android:text="@string/AddCallButtonText" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:background="@drawable/clavier_bg"/>
<Button android:id="@+id/AddCallCancelButton" android:text="@string/CancelButtonText" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:background="@drawable/clavier_bg"/>
</LinearLayout>
<LinearLayout android:id="@+id/transferCallControlRow" android:layout_height="wrap_content" android:layout_width="fill_parent" android:gravity="bottom" android:visibility="gone">
<Button android:id="@+id/TransferCallButton" android:text="@string/TransferCallButtonText" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:background="@drawable/clavier_bg"/>
<Button android:id="@+id/TransferCallCancelButton" android:text="@string/CancelButtonText" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:background="@drawable/clavier_bg"/>
</LinearLayout>
<EditText android:id="@+id/status_label" android:layout_width="fill_parent" <EditText android:id="@+id/status_label" android:layout_width="fill_parent"

View file

@ -1,16 +1,22 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" android:minHeight="60sp"
android:layout_width="fill_parent" android:layout_height="fill_parent" > 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"/> <ImageView android:id="@+id/picture" android:layout_width="wrap_content"
android:src="@drawable/unknown_person" android:layout_height="wrap_content"
android:layout_alignParentLeft="true" android:layout_centerVertical="true"
android:paddingRight="3sp"/>
<LinearLayout android:id="@+id/callee_buttons" android:layout_alignParentRight="true" <LinearLayout android:id="@+id/callee_buttons" android:layout_alignParentRight="true"
android:layout_width="wrap_content" android:layout_height="wrap_content"> android:layout_width="wrap_content" android:layout_height="fill_parent"
android:layout_centerVertical="true">
<ImageButton android:id="@+id/addVideo" android:src="@drawable/conf_video" <ImageButton android:id="@+id/addVideo" android:src="@drawable/conf_video"
android:layout_width="wrap_content" android:layout_height="wrap_content" /> android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ImageButton android:id="@+id/merge_to_conference" android:src="@drawable/conf_merge" <ImageButton android:id="@+id/merge_to_conference" android:src="@drawable/conf_merge"
android:layout_width="wrap_content" android:layout_height="wrap_content" /> android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ImageButton android:id="@+id/remove_from_conference" android:src="@drawable/conf_remove"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ImageButton android:id="@+id/unhook_call" android:src="@drawable/conf_unhook" <ImageButton android:id="@+id/unhook_call" android:src="@drawable/conf_unhook"
android:layout_width="wrap_content" android:layout_height="wrap_content" /> android:layout_width="wrap_content" android:layout_height="wrap_content" />
<ImageButton android:id="@+id/terminate_call" android:src="@drawable/conf_terminate" <ImageButton android:id="@+id/terminate_call" android:src="@drawable/conf_terminate"
@ -20,10 +26,24 @@
<ImageButton android:id="@+id/resume" android:src="@drawable/conf_resume" <ImageButton android:id="@+id/resume" android:src="@drawable/conf_resume"
android:layout_width="wrap_content" android:layout_height="wrap_content"/> android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout> </LinearLayout>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" <LinearLayout android:id="@+id/callee_statuses" android:layout_toLeftOf="@id/callee_buttons"
android:layout_toLeftOf="@id/callee_buttons" android:layout_toRightOf="@id/picture"> android:layout_width="wrap_content" android:layout_height="fill_parent"
<TextView android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content" /> android:layout_centerVertical="true">
<TextView android:id="@+id/address" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <TextView android:id="@+id/status_label" style="@style/callee_status"/>
<ImageView android:id="@+id/callee_status_paused" style="@style/callee_status" android:src="@drawable/conf_status_paused" />
<ImageView android:id="@+id/callee_status_inconf" style="@style/callee_status" android:src="@drawable/conf_status_inconf"/>
</LinearLayout>
<LinearLayout android:id="@+id/callee_block"
android:layout_toRightOf="@id/picture" android:layout_toLeftOf="@id/callee_statuses"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:layout_centerVertical="true" android:orientation="vertical">
<TextView android:id="@+id/name" style="@style/callee_name" />
<TextView android:id="@+id/address" style="@style/callee_address" android:singleLine="true"
android:ellipsize="marquee"/>
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout android:id="@+id/conf_add_all_to_conference_button"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_merge_all"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_choice_merge_all_to_conference" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/conf_enter_button"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_resume"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_admin_choice_enter" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/conf_leave_button"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_pause"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_admin_choice_leave" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/conf_terminate_button"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_terminate"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_admin_choice_terminate" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout android:id="@+id/transfer_new"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_transfer"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_choice_transfer_new" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/transfer_existing"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_transfer"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_choice_transfer_existing" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/remove_from_conference"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_remove"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_choice_remove_from_conference" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/merge_to_conference"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_merge"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_choice_merge_to_conference" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/pause"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_pause"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_choice_pause" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/resume"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_resume"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_choice_resume" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:id="@+id/terminate_call"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageButton android:src="@drawable/conf_terminate"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:text="@string/conf_choice_terminate" android:layout_gravity="center_vertical"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</ScrollView>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
@ -7,47 +7,24 @@
android:paddingRight="8dp"> android:paddingRight="8dp">
<RelativeLayout android:id="@+id/conf_header" <LinearLayout android:id="@+id/conf_header" android:layout_alignParentTop="true"
android:layout_width="fill_parent" android:layout_height="wrap_content" > android:orientation="vertical" android:layout_marginBottom="10dip"
<LinearLayout android:id="@+id/conf_management_buttons" android:layout_alignParentRight="true" android:layout_width="fill_parent" android:layout_height="wrap_content" >
android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:text="@string/conf_text_you_host_a_conference"
<Button android:id="@+id/conf_enter_or_leave_button" android:layout_alignParentRight="true" android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_height="wrap_content"/> android:gravity="center"/>
<ImageButton android:id="@+id/terminate_conference" android:src="@drawable/conf_terminate" <!-- <TextView android:id="@+id/conf_self_attending"-->
android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!-- android:layout_width="fill_parent" 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> </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"
/> <LinearLayout android:id="@+id/conf_bottom_row" android:layout_alignParentBottom="true"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<Button android:text="@string/AddCallButtonText" 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" <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" /> android:src="@drawable/mini_stopcall_red" android:layout_weight="1" />
@ -57,4 +34,36 @@
</LinearLayout> </LinearLayout>
</LinearLayout> <LinearLayout android:id="@+id/conf_menu_row"
android:layout_above="@id/conf_bottom_row"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ToggleButton android:id="@+id/toggleMuteMic" style="@style/conf_toggle_button"
android:textOn="@string/mutemic_button_txt" android:textOff="@string/mutemic_button_txt" />
<ToggleButton android:id="@+id/toggleSpeaker" style="@style/conf_toggle_button"
android:textOn="@string/speaker_button_txt" android:textOff="@string/speaker_button_txt" />
<ToggleButton android:id="@+id/toggleBluetooth" style="@style/conf_toggle_button"
android:textOn="@string/bluetooth_button_txt" android:textOff="@string/bluetooth_button_txt"
android:visibility="gone"/>
</LinearLayout>
<LinearLayout android:id="@+id/conf_simple_actions" android:visibility="visible"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_above="@id/conf_menu_row"
android:layout_centerInParent="true">
<Button android:id="@+id/conf_simple_merge" android:text="@string/conf_simple_merge" android:visibility="gone"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
android:dividerHeight="10dip"
android:divider="@android:color/transparent"
android:layout_below="@id/conf_header"
android:layout_above="@id/conf_simple_actions"
android:layout_alignWithParentIfMissing="true"
android:fadeScrollbars="false"
/>
</RelativeLayout>

View file

@ -48,6 +48,16 @@
<org.linphone.ui.HangCallButton android:id="@+id/HangUp" android:src="@drawable/stopcall_red" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="0.25" android:background="@drawable/clavier_bg"/> <org.linphone.ui.HangCallButton android:id="@+id/HangUp" android:src="@drawable/stopcall_red" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="0.25" android:background="@drawable/clavier_bg"/>
</LinearLayout> </LinearLayout>
<LinearLayout android:id="@+id/AddCallControlRow" android:layout_height="wrap_content" android:layout_width="fill_parent" android:gravity="bottom" android:visibility="gone">
<Button android:id="@+id/AddCallButton" android:text="@string/AddCallButtonText" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:background="@drawable/clavier_bg"/>
<Button android:id="@+id/AddCallCancelButton" android:text="@string/CancelButtonText" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:background="@drawable/clavier_bg"/>
</LinearLayout>
<LinearLayout android:id="@+id/transferCallControlRow" android:layout_height="wrap_content" android:layout_width="fill_parent" android:gravity="bottom" android:visibility="gone">
<Button android:id="@+id/TransferCallButton" android:text="@string/TransferCallButtonText" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:background="@drawable/clavier_bg"/>
<Button android:id="@+id/TransferCallCancelButton" android:text="@string/CancelButtonText" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_weight="1" android:background="@drawable/clavier_bg"/>
</LinearLayout>
<EditText android:id="@+id/status_label" android:clickable="false" android:focusable="false" android:cursorVisible="false" android:textSize="12sp" android:height="15sp" android:layout_height="wrap_content" android:layout_width="fill_parent" android:background="@android:color/transparent" android:textColor="@android:color/white" /> <EditText android:id="@+id/status_label" android:clickable="false" android:focusable="false" android:cursorVisible="false" android:textSize="12sp" android:height="15sp" android:layout_height="wrap_content" android:layout_width="fill_parent" android:background="@android:color/transparent" android:textColor="@android:color/white" />
</LinearLayout> </LinearLayout>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="callee_name" parent="@android:style/TextAppearance.Medium">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_weight">1</item>
</style>
<style name="callee_address" parent="@android:style/TextAppearance">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_weight">1</item>
</style>
<style name="callee_status">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:gravity">center_vertical</item>
<item name="android:layout_gravity">center_vertical</item>
<item name="android:scaleType">center</item>
</style>
<style name="conf_toggle_button" parent="@android:style/Widget.Button.Toggle">
<item name="android:width">0px</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<!-- <item name="android:layout_width">wrap_content</item>-->
<!-- <item name="android:layout_height">wrap_content</item>-->
</style>
</resources>

View file

@ -18,6 +18,7 @@
<bool name="allow_edit_in_dialer">true</bool> <bool name="allow_edit_in_dialer">true</bool>
<string name="notification_registered">Registered to %s </string> <string name="notification_registered">Registered to %s </string>
<string name="notification_register_failure">Fails to register to %s</string> <string name="notification_register_failure">Fails to register to %s</string>
<color name="conf_active_bg_color">#191970</color>
<string name="about_text">Linphone %s SIP (rfc 3261) compatible phone under GNU Public License V2\n http://www.linphone.org\n\nInstructions\nhttp://www.linphone.org/m/help\n\n© 2011 Belledonne Communications</string> <string name="about_text">Linphone %s SIP (rfc 3261) compatible phone under GNU Public License V2\n http://www.linphone.org\n\nInstructions\nhttp://www.linphone.org/m/help\n\n© 2011 Belledonne Communications</string>
<string name="about_bugreport_email">linphone-android@belledonne-communications.com</string> <string name="about_bugreport_email">linphone-android@belledonne-communications.com</string>

View file

@ -1,6 +1,37 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="status_conf_call">conf</string>
<string name="status_active_call">active</string>
<string name="state_paused">paused</string>
<string name="state_paused_by_remote">paused</string>
<string name="state_streams_running"></string>
<string name="state_incoming_received">incoming</string>
<string name="state_outgoing_ringing">ringing</string>
<string name="mutemic_button_txt">Mute</string>
<string name="speaker_button_txt">Speaker</string>
<string name="bluetooth_button_txt">Bluetooth</string>
<string name="CancelButtonText">Cancel</string>
<string name="AddCallButtonText">Add call</string>
<string name="TransferCallButtonText">Transfer call</string>
<string name="conf_admin_choice_enter">Enter conference</string>
<string name="conf_admin_choice_leave">Momentarily leave conference</string>
<string name="conf_admin_choice_terminate">Terminate conference</string>
<string name="conf_choice_transfer_existing">Transfer to existing call</string>
<string name="conf_choice_transfer_new">Transfer to new call</string>
<string name="conf_choice_resume">Resume</string>
<string name="conf_choice_pause">Pause</string>
<string name="conf_choice_merge_to_conference">Add to conference</string>
<string name="conf_choice_merge_all_to_conference">Add all calls to conference</string>
<string name="conf_choice_remove_from_conference">Remove from the conference</string>
<string name="conf_choice_terminate">Terminate</string>
<string name="conf_simple_merge">Merge calls</string>
<string name="show_send_dtmfs_button">DTMFs</string> <string name="show_send_dtmfs_button">DTMFs</string>
<string name="conf_text_you_host_a_conference">You host a conference</string> <string name="conf_text_you_host_a_conference">You host a conference</string>

View file

@ -4,16 +4,16 @@
<PreferenceCategory android:title="@string/pref_sipaccount"> <PreferenceCategory android:title="@string/pref_sipaccount">
<EditTextPreference android:title="@string/pref_username" <EditTextPreference android:title="@string/pref_username"
android:key="@string/pref_username_key"></EditTextPreference> android:key="@string/pref_username_key" android:inputType="text|textEmailAddress"></EditTextPreference>
<EditTextPreference android:title="@string/pref_passwd" <EditTextPreference android:title="@string/pref_passwd"
android:key="@string/pref_passwd_key" android:password="true"></EditTextPreference> android:key="@string/pref_passwd_key" android:password="true"></EditTextPreference>
<EditTextPreference android:title="@string/pref_domain" <EditTextPreference android:title="@string/pref_domain"
android:key="@string/pref_domain_key"></EditTextPreference> android:key="@string/pref_domain_key" android:inputType="text|textEmailAddress"></EditTextPreference>
<EditTextPreference android:title="@string/pref_proxy" <EditTextPreference android:title="@string/pref_proxy"
android:key="@string/pref_proxy_key"></EditTextPreference> android:key="@string/pref_proxy_key" android:inputType="text|textEmailAddress"></EditTextPreference>
<CheckBoxPreference android:enabled="true" <CheckBoxPreference android:enabled="true"
android:selectable="true" android:key="@string/pref_enable_outbound_proxy_key" android:selectable="true" android:key="@string/pref_enable_outbound_proxy_key"

View file

@ -18,36 +18,50 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
package org.linphone; package org.linphone;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import org.linphone.LinphoneSimpleListener.LinphoneOnCallStateChangedListener; import org.linphone.LinphoneSimpleListener.LinphoneOnCallStateChangedListener;
import org.linphone.core.Hacks;
import org.linphone.core.LinphoneCall; import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreException;
import org.linphone.core.Log; import org.linphone.core.Log;
import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCall.State;
import org.linphone.mediastream.video.capture.hwconf.Hacks;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.ListActivity; import android.app.ListActivity;
import android.graphics.Color; import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
/**
* @author Guillaume Beraudo
*/
public class ConferenceActivity extends ListActivity implements public class ConferenceActivity extends ListActivity implements
LinphoneOnCallStateChangedListener, Comparator<LinphoneCall>, LinphoneOnCallStateChangedListener, Comparator<LinphoneCall>,
OnClickListener { OnClickListener {
private View confHeaderView; private View confHeaderView;
static boolean active;
// Start Override to test block // Start Override to test block
protected LinphoneCore lc() { protected LinphoneCore lc() {
@ -66,31 +80,35 @@ public class ConferenceActivity extends ListActivity implements
// End override to test block // 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; private static final int numpad_dialog_id = 1;
public static final String ADD_CALL = "add_call";
public static final String TRANSFER_TO_NEW_CALL = "transfer_to_new_call";
public static final String CALL_NATIVE_ID = "call_native_id";
private void workaroundStatusBarBug() {
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.conferencing); setContentView(R.layout.conferencing);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
confHeaderView = findViewById(R.id.conf_header); confHeaderView = findViewById(R.id.conf_header);
confHeaderView.findViewById(R.id.terminate_conference) confHeaderView.setOnClickListener(this);
.setOnClickListener(this);
confHeaderView.findViewById(R.id.conf_enter_or_leave_button)
.setOnClickListener(this);
findViewById(R.id.addCall).setOnClickListener(this); findViewById(R.id.addCall).setOnClickListener(this);
findViewById(R.id.incallHang).setOnClickListener(this); findViewById(R.id.incallHang).setOnClickListener(this);
findViewById(R.id.incallNumpadShow).setOnClickListener(this); findViewById(R.id.incallNumpadShow).setOnClickListener(this);
findViewById(R.id.conf_simple_merge).setOnClickListener(this);
List<LinphoneCall> calls = getInitialCalls(); List<LinphoneCall> calls = getInitialCalls();
setListAdapter(new CalleeListAdapter(calls)); setListAdapter(new CalleeListAdapter(calls));
workaroundStatusBarBug();
updateConfState();
} }
protected void registerLinphoneListener(boolean register) { protected void registerLinphoneListener(boolean register) {
@ -102,30 +120,44 @@ public class ConferenceActivity extends ListActivity implements
@Override @Override
protected void onResume() { protected void onResume() {
active=true;
registerLinphoneListener(true); registerLinphoneListener(true);
updateConfState();
super.onResume(); super.onResume();
} }
@Override @Override
protected void onPause() { protected void onPause() {
active=false;
registerLinphoneListener(false); registerLinphoneListener(false);
super.onPause(); super.onPause();
} }
private void enableView(View root, int id, OnClickListener l, boolean enable) {
View v = root.findViewById(id);
v.setVisibility(enable ? VISIBLE : GONE);
v.setOnClickListener(l);
}
@Override @Override
protected Dialog onCreateDialog(final int id) { protected Dialog onCreateDialog(final int id) {
return new AlertDialog.Builder(this).setView( switch (id) {
getLayoutInflater().inflate(R.layout.numpad, null)) case numpad_dialog_id:
// .setIcon(R.drawable.logo_linphone_57x57) return new AlertDialog.Builder(this).setView(
// .setTitle("Send DTMFs") getLayoutInflater().inflate(R.layout.numpad, null))
// .setPositiveButton("hide", new // .setIcon(R.drawable.logo_linphone_57x57)
// DialogInterface.OnClickListener() { // .setTitle("Send DTMFs")
// public void onClick(DialogInterface dialog, int whichButton) // .setPositiveButton("hide", new
// { // DialogInterface.OnClickListener() {
// dismissDialog(id); // public void onClick(DialogInterface dialog, int whichButton)
// } // {
// }) // dismissDialog(id);
.create(); // }
// })
.create();
default:
throw new RuntimeException("unkown dialog id " + id);
}
} }
// protected void conferenceMerge(boolean hostInTheConference, LinphoneCall // protected void conferenceMerge(boolean hostInTheConference, LinphoneCall
@ -142,23 +174,20 @@ public class ConferenceActivity extends ListActivity implements
} }
private final void updateConfState() { private final void updateConfState() {
if (lc().getCallsNb() == 0) if (lc().getCallsNb() == 0) {
setResult(RESULT_OK);
finish(); finish();
}
boolean inConf = lc().isInConference(); boolean inConf = lc().isInConference();
confHeaderView.setBackgroundColor(inConf ? ACTIVE_BG_COLOR
: INACTIVE_BG_COLOR);
confHeaderView int bgColor = getResources().getColor(inConf? R.color.conf_active_bg_color : android.R.color.transparent);
.setVisibility(lc().getConferenceSize() > 0 ? View.VISIBLE confHeaderView.setBackgroundColor(bgColor);
: View.GONE); confHeaderView.setVisibility(lc().getConferenceSize() > 0 ? VISIBLE: GONE);
TextView v = (TextView) confHeaderView // TextView v = (TextView) confHeaderView
.findViewById(R.id.conf_self_attending); // .findViewById(R.id.conf_self_attending);
v.setText(inConf ? R.string.in_conf : R.string.out_conf); // 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) { public void onClick(View v) {
@ -169,31 +198,125 @@ public class ConferenceActivity extends ListActivity implements
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
// startActivityForResult(new Intent().setClass(this, // startActivityForResult(new Intent().setClass(this,
// LinphoneContactSelectorActivity.class), 0); // LinphoneContactSelectorActivity.class), 0);
lc().pauseAllCalls();
setResult(RESULT_OK, new Intent().putExtra(ADD_CALL, true));
finish();
break; break;
case R.id.conf_enter_or_leave_button: case R.id.conf_header:
if (lc().isInConference()) { View content = getLayoutInflater().inflate(R.layout.conf_choices_admin, null);
lc().leaveConference(); final Dialog dialog = new AlertDialog.Builder(ConferenceActivity.this).setView(content).create();
} else { boolean isInConference = lc().isInConference();
lc().enterConference(); OnClickListener l = new OnClickListener() {
} public void onClick(View v) {
break; switch (v.getId()) {
case R.id.terminate_conference: case R.id.conf_add_all_to_conference_button:
lc().terminateConference(); lc().addAllToConference();
findViewById(R.id.conf_header).setVisibility(View.GONE); break;
case R.id.conf_enter_button:
lc().enterConference();
break;
case R.id.conf_leave_button:
lc().leaveConference();
break;
case R.id.conf_terminate_button:
lc().terminateConference();
findViewById(R.id.conf_header).setVisibility(GONE);
break;
default:
break;
}
dialog.dismiss();
}
};
enableView(content, R.id.conf_enter_button, l, !isInConference);
enableView(content, R.id.conf_leave_button, l, isInConference);
content.findViewById(R.id.conf_terminate_button).setOnClickListener(l);
content.findViewById(R.id.conf_add_all_to_conference_button).setOnClickListener(l);
dialog.show();
break; break;
case R.id.incallHang: case R.id.incallHang:
lc().terminateAllCalls(); lc().terminateAllCalls();
setResult(RESULT_OK);
finish(); finish();
break; break;
case R.id.incallNumpadShow: case R.id.incallNumpadShow:
showDialog(numpad_dialog_id); showDialog(numpad_dialog_id);
break; break;
case R.id.conf_simple_merge:
lc().addAllToConference();
break;
default: default:
break; break;
} }
} }
private class CallActionListener implements OnClickListener {
private LinphoneCall call;
private Dialog dialog;
public CallActionListener(LinphoneCall call, Dialog dialog) {
this.call = call;
this.dialog = dialog;
}
public CallActionListener(LinphoneCall call) {
this.call = call;
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.merge_to_conference:
lc().addToConference(call);
break;
case R.id.terminate_call:
lc().terminateCall(call);
break;
case R.id.pause:
lc().pauseCall(call);
break;
case R.id.resume:
lc().resumeCall(call);
break;
case R.id.unhook_call:
LinphoneCall currentCall = lc().getCurrentCall();
if (currentCall != null) lc().pauseCall(currentCall);
try {
lc().acceptCall(call);
} catch (LinphoneCoreException e) {
throw new RuntimeException(e);
}
break;
case R.id.transfer_existing:
Toast.makeText(ConferenceActivity.this, "Transfer choice selected", Toast.LENGTH_LONG).show();
@SuppressWarnings("unchecked") final List<LinphoneCall> existingCalls = lc().getCalls();
existingCalls.remove(call);
final List<String> numbers = new ArrayList<String>(existingCalls.size());
Resources r = getResources();
for(LinphoneCall c : existingCalls) {
numbers.add(LinphoneManager.extractADisplayName(r, c.getRemoteAddress()));
}
ListAdapter adapter = new ArrayAdapter<String>(ConferenceActivity.this, android.R.layout.select_dialog_item, numbers);
DialogInterface.OnClickListener l = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
lc().transferCallToAnother(call, existingCalls.get(which));
}
};
new AlertDialog.Builder(ConferenceActivity.this).setAdapter(adapter, l).create().show();
break;
case R.id.transfer_new:
Toast.makeText(ConferenceActivity.this, "Transfer choice selected : to do, create activity to select new call", Toast.LENGTH_LONG).show();
// setResult(RESULT_OK, new Intent().putExtra(TRANSFER_TO_NEW_CALL, true));
// setResult(RESULT_OK, new Intent().putExtra(CALL_NATIVE_ID, Hacks.ptrOf(call)));
// finish();
break;
case R.id.remove_from_conference:
lc().removeFromConference(call);
break;
default:
throw new RuntimeException("unknown id " + v.getId());
}
if (dialog != null) dialog.dismiss();
}
}
private class CalleeListAdapter extends BaseAdapter { private class CalleeListAdapter extends BaseAdapter {
private List<LinphoneCall> linphoneCalls; private List<LinphoneCall> linphoneCalls;
@ -219,10 +342,10 @@ public class ConferenceActivity extends ListActivity implements
return false; return false;
int count = 0; int count = 0;
for (LinphoneCall call : linphoneCalls) { for (LinphoneCall call : linphoneCalls) {
int stateId = call.getState().value(); final LinphoneCall.State state = call.getState();
boolean connectionEstablished = stateId == State.ID_STREAMS_RUNNING boolean connectionEstablished = state == State.StreamsRunning
|| stateId == State.ID_PAUSED || state == State.Paused
|| stateId == State.ID_PAUSED_BY_REMOTE; || state == State.PausedByRemote;
if (connectionEstablished) if (connectionEstablished)
count++; count++;
if (count >= 2) if (count >= 2)
@ -231,137 +354,166 @@ public class ConferenceActivity extends ListActivity implements
return false; return false;
} }
private void setVisibility(View v, int id, boolean visible) {
v.findViewById(id).setVisibility(visible ? VISIBLE : GONE);
}
private void setVisibility(View v, boolean visible) {
v.setVisibility(visible ? VISIBLE : GONE);
}
private void setStatusLabel(View v, State state, boolean inConf, boolean activeOne) {
String statusLabel = getStateText(state);
if (activeOne)
statusLabel=getString(R.string.status_active_call);
if (inConf)
statusLabel=getString(R.string.status_conf_call);
((TextView) v.findViewById(R.id.status_label)).setText(statusLabel);
}
public View getView(int position, View v, ViewGroup parent) { public View getView(int position, View v, ViewGroup parent) {
if (v == null) { if (v == null) {
v = getLayoutInflater().inflate(R.layout.conf_callee, null); v = getLayoutInflater().inflate(R.layout.conf_callee, null);
} }
LinphoneCall call = linphoneCalls.get(position); final LinphoneCall call = linphoneCalls.get(position);
int stateId = call.getState().value(); final LinphoneCall.State state = call.getState();
((TextView) v.findViewById(R.id.name)).setText(call ((TextView) v.findViewById(R.id.name)).setText(call
.getRemoteAddress().getDisplayName()); .getRemoteAddress().getDisplayName());
((TextView) v.findViewById(R.id.address)).setText(call ((TextView) v.findViewById(R.id.address)).setText(call
.getRemoteAddress().getUserName()); .getRemoteAddress().getUserName());
boolean isInConference = call.isInConference(); final boolean isInConference = call.isInConference();
boolean currentlyActiveCall = !isInConference boolean currentlyActiveCall = !isInConference
&& stateId == State.ID_STREAMS_RUNNING; && state == State.StreamsRunning;
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 setStatusLabel(v, state, isInConference, currentlyActiveCall);
|| stateId == State.ID_PAUSED
|| stateId == State.ID_PAUSED_BY_REMOTE;
int bgDrawableId = R.drawable.conf_callee_selector_normal;
if (state == State.IncomingReceived) {
bgDrawableId = R.drawable.conf_callee_selector_incoming;
} else if (currentlyActiveCall) {
bgDrawableId = R.drawable.conf_callee_selector_active;
} else if (isInConference) {
bgDrawableId = R.drawable.conf_callee_selector_inconf;
}
v.setBackgroundResource(bgDrawableId);
boolean connectionEstablished = state == State.StreamsRunning
|| state == State.Paused
|| state == State.PausedByRemote;
View confButton = v.findViewById(R.id.merge_to_conference); View confButton = v.findViewById(R.id.merge_to_conference);
boolean showMergeToConf = !isInConference && connectionEstablished final boolean showMergeToConf = !isInConference && connectionEstablished
&& aConferenceIsPossible(); && aConferenceIsPossible();
confButton setVisibility(confButton, false);
.setVisibility(showMergeToConf ? View.VISIBLE : View.GONE);
View unhookCallButton = v.findViewById(R.id.unhook_call); View unhookCallButton = v.findViewById(R.id.unhook_call);
boolean showUnhook = stateId == State.ID_INCOMING_RECEIVED; boolean showUnhook = state == State.IncomingReceived;
unhookCallButton.setVisibility(showUnhook ? View.VISIBLE setVisibility(unhookCallButton, showUnhook);
: View.GONE);
View terminateCallButton = v.findViewById(R.id.terminate_call); View terminateCallButton = v.findViewById(R.id.terminate_call);
terminateCallButton.setVisibility(!isInConference ? View.VISIBLE boolean showTerminate = state == State.IncomingReceived;
: View.GONE); setVisibility(terminateCallButton, showTerminate);
View pauseButton = v.findViewById(R.id.pause); View pauseButton = v.findViewById(R.id.pause);
boolean showPause = !isInConference final boolean showPause = !isInConference
&& call.getState().equals(State.StreamsRunning); && state == State.StreamsRunning;
pauseButton.setVisibility(showPause ? View.VISIBLE : View.GONE); setVisibility(pauseButton, false);
View resumeButton = v.findViewById(R.id.resume); View resumeButton = v.findViewById(R.id.resume);
boolean showResume = !isInConference final boolean showResume = !isInConference
&& call.getState().equals(State.Paused); && state == State.Paused;
resumeButton.setVisibility(showResume ? View.VISIBLE : View.GONE); setVisibility(resumeButton, false);
v.findViewById(R.id.addVideo).setVisibility( View removeFromConfButton = v.findViewById(R.id.remove_from_conference);
!showUnhook && linphoneCalls.size() == 1 ? View.VISIBLE setVisibility(removeFromConfButton, false);
: View.GONE);
setVisibility(v, R.id.addVideo, !showUnhook && linphoneCalls.size() == 1);
createAndAttachCallViewClickListener(position, confButton, boolean statusPaused = state== State.Paused || state == State.PausedByRemote;
unhookCallButton, terminateCallButton, pauseButton, setVisibility(v, R.id.callee_status_paused, statusPaused);
resumeButton);
return v;
}
private void createAndAttachCallViewClickListener(final int position, setVisibility(v, R.id.callee_status_inconf, isInConference);
final View confButton, final View unhookCallButton,
final View terminateCallButton, final View pauseButton, final OnClickListener l = new CallActionListener(call);
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); confButton.setOnClickListener(l);
terminateCallButton.setOnClickListener(l); terminateCallButton.setOnClickListener(l);
pauseButton.setOnClickListener(l); pauseButton.setOnClickListener(l);
resumeButton.setOnClickListener(l); resumeButton.setOnClickListener(l);
unhookCallButton.setOnClickListener(l); unhookCallButton.setOnClickListener(l);
removeFromConfButton.setOnClickListener(l);
v.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
View content = getLayoutInflater().inflate(R.layout.conf_choices_dialog, null);
Dialog dialog = new AlertDialog.Builder(ConferenceActivity.this).setView(content).create();
OnClickListener l = new CallActionListener(call, dialog);
enableView(content, R.id.transfer_existing, l, !isInConference);
enableView(content, R.id.transfer_new, l, !isInConference);
enableView(content, R.id.remove_from_conference, l, isInConference);
enableView(content, R.id.merge_to_conference, l, showMergeToConf);
enableView(content, R.id.pause, l,!isInConference && showPause);
enableView(content, R.id.resume, l, !isInConference && showResume);
enableView(content, R.id.terminate_call, l, true);
dialog.show();
}
});
return v;
} }
} }
private String getStateText(State state) {
int id;
if (state == State.IncomingReceived) {
id=R.string.state_incoming_received;
} else if (state == State.OutgoingRinging) {
id=R.string.state_outgoing_ringing;
} else if (state == State.Paused) {
id=R.string.state_paused;
} else if (state == State.PausedByRemote) {
id=R.string.state_paused_by_remote;
} else {
return "";
}
return getString(id);
}
private Handler mHandler = new Handler(); private Handler mHandler = new Handler();
public void onCallStateChanged(final LinphoneCall call, final State state, public void onCallStateChanged(final LinphoneCall call, final State state,
final String message) { final String message) {
final String stateStr = call + " " + state.toString();
Log.d("ConferenceActivity received state ",stateStr);
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
public void run() { public void run() {
CalleeListAdapter adapter = (CalleeListAdapter) getListAdapter(); CalleeListAdapter adapter = (CalleeListAdapter) getListAdapter();
Log.d("ConferenceActivity applying state ",stateStr);
String stateStr = call + " " + state.toString(); boolean showSimpleActions = lc().getConferenceSize() == 0 && lc().getCallsNb() == 2;
Log.d("ConferenceActivity received state ",stateStr); findViewById(R.id.conf_simple_merge).setVisibility(showSimpleActions ? VISIBLE : GONE);
switch (state.value()) { if (state == State.IncomingReceived || state == State.OutgoingRinging) {
case State.ID_INCOMING_RECEIVED: if (!adapter.linphoneCalls.contains(call)) {
case State.ID_OUTGOING_RINGING: adapter.linphoneCalls.add(call);
adapter.linphoneCalls.add(call); Collections.sort(adapter.linphoneCalls,
Collections.sort(adapter.linphoneCalls, ConferenceActivity.this);
ConferenceActivity.this); adapter.notifyDataSetInvalidated();
adapter.notifyDataSetInvalidated(); adapter.notifyDataSetChanged();
break; } else {
case State.ID_PAUSED: Log.e("Call should not be in the call lists : " + stateStr);
case State.ID_PAUSED_BY_REMOTE: }
case State.ID_STREAMS_RUNNING: } else if (state == State.Paused || state == State.PausedByRemote || state == State.StreamsRunning) {
Collections.sort(adapter.linphoneCalls, Collections.sort(adapter.linphoneCalls,
ConferenceActivity.this); ConferenceActivity.this);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
break; } else if (state == State.CallEnd) {
case State.ID_CALL_END:
adapter.linphoneCalls.remove(call); adapter.linphoneCalls.remove(call);
Collections.sort(adapter.linphoneCalls, Collections.sort(adapter.linphoneCalls,
ConferenceActivity.this); ConferenceActivity.this);
adapter.notifyDataSetInvalidated(); adapter.notifyDataSetInvalidated();
break; adapter.notifyDataSetChanged();
default:
break;
} }
updateConfState(); updateConfState();
@ -400,17 +552,17 @@ public class ConferenceActivity extends ListActivity implements
* // bellow, ringings and incoming int c1State = c1.getState().value(); int * // bellow, ringings and incoming int c1State = c1.getState().value(); int
* c2State = c2.getState().value(); * c2State = c2.getState().value();
* *
* boolean c1StateIsEstablishing = c1State == State.ID_INCOMING_RECEIVED || * boolean c1StateIsEstablishing = c1State == State.IncomingReceived ||
* c1State == State.ID_OUTGOING_RINGING; boolean c2StateIsEstablishing = * c1State == State.ID_OUTGOING_RINGING; boolean c2StateIsEstablishing =
* c2State == State.ID_INCOMING_RECEIVED || c2State == * c2State == State.IncomingReceived || c2State ==
* State.ID_OUTGOING_RINGING; * State.ID_OUTGOING_RINGING;
* *
* // Xor only one establishing state if (c1StateIsEstablishing ^ * // Xor only one establishing state if (c1StateIsEstablishing ^
* c2StateIsEstablishing) { // below return !c1StateIsEstablishing ? -1 : 1; * c2StateIsEstablishing) { // below return !c1StateIsEstablishing ? -1 : 1;
* } * }
* *
* // Xor only one paused state if (c1State == State.ID_PAUSED ^ c2State == * // Xor only one paused state if (c1State == State.Paused ^ c2State ==
* State.ID_PAUSED) { return c1State == State.ID_PAUSED ? -1 : 1; } * State.Paused) { return c1State == State.Paused ? -1 : 1; }
* *
* return compUserName; //Duration() - c1.getDuration(); } * return compUserName; //Duration() - c1.getDuration(); }
*/ */

View file

@ -27,6 +27,7 @@ import org.linphone.core.LinphoneCore;
import org.linphone.core.Log; import org.linphone.core.Log;
import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCall.State;
import org.linphone.mediastream.Version; import org.linphone.mediastream.Version;
import org.linphone.mediastream.video.capture.hwconf.Hacks;
import org.linphone.ui.AddVideoButton; import org.linphone.ui.AddVideoButton;
import org.linphone.ui.AddressAware; import org.linphone.ui.AddressAware;
import org.linphone.ui.AddressText; import org.linphone.ui.AddressText;
@ -47,6 +48,7 @@ import android.os.Bundle;
import android.os.PowerManager; import android.os.PowerManager;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -311,7 +313,8 @@ public class DialerActivity extends LinphoneManagerWaitActivity implements Linph
@Override @Override
protected void onPrepareDialog(int id, Dialog dialog) { protected void onPrepareDialog(int id, Dialog dialog) {
if (id == incomingCallDialogId) { if (id == incomingCallDialogId) {
String from = LinphoneManager.getInstance().extractIncomingRemoteName(); LinphoneAddress address = LinphoneManager.getLc().getRemoteAddress();
String from = LinphoneManager.extractIncomingRemoteName(getResources(), address);
String msg = String.format(getString(R.string.incoming_call_dialog_title), from); String msg = String.format(getString(R.string.incoming_call_dialog_title), from);
((AlertDialog) dialog).setMessage(msg); ((AlertDialog) dialog).setMessage(msg);
} else { } else {
@ -490,5 +493,56 @@ public class DialerActivity extends LinphoneManagerWaitActivity implements Linph
} }
super.onResume(); super.onResume();
} }
private void switchControlRow(ViewGroup v, OnClickListener l) {
final View ok = v.getChildAt(0);
final View cancel = v.getChildAt(1);
ok.setOnClickListener(l);
cancel.setOnClickListener(l);
findViewById(R.id.IncallControlRow).setVisibility(View.GONE);
findViewById(R.id.CallControlRow).setVisibility(View.GONE);
v.setVisibility(View.VISIBLE);
}
public void configureForAddingCall() {
ViewGroup v = (ViewGroup) findViewById(R.id.AddCallControlRow);
OnClickListener l = new OnClickListener() {
public void onClick(View v) {
ViewGroup group = (ViewGroup) v.getParent();
if (v == group.getChildAt(1)) {
LinphoneActivity.instance().startConferenceActivity();
} else {
LinphoneManager.getInstance().newOutgoingCall(mAddress);
}
}
};
switchControlRow(v, l);
}
public void configureForTransferingCall(final long callNativeId) {
throw new RuntimeException("create another activity for this");
// ViewGroup v = (ViewGroup) findViewById(R.id.transferCallControlRow);
// OnClickListener l = new OnClickListener() {
// public void onClick(View v) {
// ViewGroup group = (ViewGroup) v.getParent();
// if (v == group.getChildAt(1)) {
// LinphoneActivity.instance().startConferenceActivity();
// } else {
// LinphoneManager.getLc().transferCall(Hacks.createCall(callNativeId),
// mAddress.getText().toString());
// }
// }
// };
// switchControlRow(v, l);
}
public void configureForDialer() {
findViewById(R.id.AddCallControlRow).setVisibility(R.id.transferCallControlRow);
findViewById(R.id.AddCallControlRow).setVisibility(View.GONE);
findViewById(R.id.IncallControlRow).setVisibility(View.GONE);
findViewById(R.id.CallControlRow).setVisibility(View.VISIBLE);
}
} }

View file

@ -150,8 +150,8 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
if (requestCode == FIRST_LOGIN_ACTIVITY) { case FIRST_LOGIN_ACTIVITY:
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
Toast.makeText(this, getString(R.string.ec_calibration_launch_message), Toast.LENGTH_LONG).show(); Toast.makeText(this, getString(R.string.ec_calibration_launch_message), Toast.LENGTH_LONG).show();
try { try {
@ -172,6 +172,22 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
finish(); finish();
stopService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class)); stopService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
} }
break;
case conference_activity:
if (data == null) {
DialerActivity.instance().configureForDialer();
} else if (data.getBooleanExtra(ConferenceActivity.ADD_CALL, false)) {
DialerActivity.instance().configureForAddingCall();
gotToDialer();
} else if (data.getBooleanExtra(ConferenceActivity.TRANSFER_TO_NEW_CALL, false)) {
long callId = data.getLongExtra(ConferenceActivity.CALL_NATIVE_ID, 0l);
if (callId == 0) throw new RuntimeException("call id is 0");
DialerActivity.instance().configureForTransferingCall(callId);
gotToDialer();
}
break;
default:
break;
} }
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
@ -507,6 +523,8 @@ public class LinphoneActivity extends TabActivity implements SensorEventListener
} }
public void startConferenceActivity() { public void startConferenceActivity() {
if (ConferenceActivity.active) return;
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
public void run() { public void run() {
startActivityForResult(new Intent().setClass( startActivityForResult(new Intent().setClass(

View file

@ -45,7 +45,6 @@ import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import org.linphone.LinphoneSimpleListener.LinphoneServiceListener; import org.linphone.LinphoneSimpleListener.LinphoneServiceListener;
import org.linphone.core.Hacks;
import org.linphone.core.LinphoneAddress; import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAuthInfo; import org.linphone.core.LinphoneAuthInfo;
import org.linphone.core.LinphoneCall; import org.linphone.core.LinphoneCall;
@ -258,10 +257,10 @@ public final class LinphoneManager implements LinphoneCoreListener {
public void newOutgoingCall(AddressType address) { public void newOutgoingCall(AddressType address) {
String to = address.getText().toString(); String to = address.getText().toString();
if (mLc.isIncall()) { // if (mLc.isIncall()) {
listenerDispatcher.tryingNewOutgoingCallButAlreadyInCall(); // listenerDispatcher.tryingNewOutgoingCallButAlreadyInCall();
return; // return;
} // }
LinphoneAddress lAddress; LinphoneAddress lAddress;
try { try {
lAddress = mLc.interpretUrl(to); lAddress = mLc.interpretUrl(to);

View file

@ -22,7 +22,6 @@ import java.io.IOException;
import org.linphone.LinphoneManager.NewOutgoingCallUiListener; import org.linphone.LinphoneManager.NewOutgoingCallUiListener;
import org.linphone.LinphoneSimpleListener.LinphoneServiceListener; import org.linphone.LinphoneSimpleListener.LinphoneServiceListener;
import org.linphone.core.Hacks;
import org.linphone.core.LinphoneCall; import org.linphone.core.LinphoneCall;
import org.linphone.core.Log; import org.linphone.core.Log;
import org.linphone.core.OnlineStatus; import org.linphone.core.OnlineStatus;

View file

@ -477,7 +477,7 @@ class LinphoneCoreImpl implements LinphoneCore {
public synchronized void setZrtpSecretsCache(String file) { public synchronized void setZrtpSecretsCache(String file) {
setZrtpSecretsCache(nativePtr,file); setZrtpSecretsCache(nativePtr,file);
} }
public void enableEchoLimiter(boolean val) { public synchronized void enableEchoLimiter(boolean val) {
enableEchoLimiter(nativePtr,val); enableEchoLimiter(nativePtr,val);
} }
public void setVideoDevice(int id) { public void setVideoDevice(int id) {
@ -492,43 +492,38 @@ class LinphoneCoreImpl implements LinphoneCore {
private native void leaveConference(long nativePtr); private native void leaveConference(long nativePtr);
public void leaveConference() { public synchronized void leaveConference() {
leaveConference(nativePtr); leaveConference(nativePtr);
} }
private native void enterConference(long nativePtr); private native void enterConference(long nativePtr);
public void enterConference() { public synchronized void enterConference() {
enterConference(nativePtr); enterConference(nativePtr);
} }
private native boolean isInConference(long nativePtr); private native boolean isInConference(long nativePtr);
public boolean isInConference() { public synchronized boolean isInConference() {
return isInConference(nativePtr); 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); private native void terminateConference(long nativePtr);
public void terminateConference() { public synchronized void terminateConference() {
terminateConference(nativePtr); terminateConference(nativePtr);
} }
private native int getConferenceSize(long nativePtr); private native int getConferenceSize(long nativePtr);
public int getConferenceSize() { public synchronized int getConferenceSize() {
return getConferenceSize(nativePtr); return getConferenceSize(nativePtr);
} }
private native int getCallsNb(long nativePtr); private native int getCallsNb(long nativePtr);
public int getCallsNb() { public synchronized int getCallsNb() {
return getCallsNb(nativePtr); return getCallsNb(nativePtr);
} }
private native void terminateAllCalls(long nativePtr); private native void terminateAllCalls(long nativePtr);
public void terminateAllCalls() { public synchronized void terminateAllCalls() {
terminateAllCalls(nativePtr); terminateAllCalls(nativePtr);
} }
private native long getCall(long nativePtr, int position); private native long getCall(long nativePtr, int position);
@SuppressWarnings("unchecked") public List getCalls() { @SuppressWarnings("unchecked") public synchronized List getCalls() {
int size = getCallsNb(nativePtr); int size = getCallsNb(nativePtr);
List<LinphoneCall> calls = new ArrayList<LinphoneCall>(size); List<LinphoneCall> calls = new ArrayList<LinphoneCall>(size);
for (int i=0; i < size; i++) { for (int i=0; i < size; i++) {
@ -537,27 +532,31 @@ class LinphoneCoreImpl implements LinphoneCore {
return calls; return calls;
} }
private native void addAllToConference(long nativePtr); private native void addAllToConference(long nativePtr);
public void addAllToConference() { public synchronized void addAllToConference() {
addAllToConference(nativePtr); addAllToConference(nativePtr);
} }
private native void addToConference(long nativePtr); private native void addToConference(long nativePtr, long nativePtrLcall);
public void addToConference(LinphoneCall call) { public synchronized void addToConference(LinphoneCall call) {
addToConference(nativePtr); addToConference(nativePtr, getCallPtr(call));
} }
private native void removeFromConference(long nativePtr); private native void removeFromConference(long nativePtr);
public void removeFromConference(LinphoneCall call) { public synchronized void removeFromConference(LinphoneCall call) {
removeFromConference(nativePtr); removeFromConference(getCallPtr(call));
} }
public void transferCall(LinphoneCall call, String referTo) { private long getCallPtr(LinphoneCall call) {
// TODO Auto-generated method stub return ((LinphoneCallImpl)call).nativePtr;
} }
public void transferCallToAnother(LinphoneCall callToTransfer,
LinphoneCall destination) { private native int transferCall(long nativePtr, long callPtr, String referTo);
// TODO Auto-generated method stub public synchronized void transferCall(LinphoneCall call, String referTo) {
transferCall(nativePtr, getCallPtr(call), referTo);
}
private native int transferCallToAnother(long nativePtr, long callPtr, long destPtr);
public synchronized void transferCallToAnother(LinphoneCall call, LinphoneCall dest) {
transferCallToAnother(nativePtr, getCallPtr(call), getCallPtr(dest));
} }
} }

View file

@ -59,6 +59,14 @@ public class TestConferenceActivity extends ConferenceActivity {
} }
}, millis); }, millis);
} }
private void delayedCallEvent(final LinphoneCall call, final State targetState, int millis) {
mHandler.postDelayed(new Runnable() {
public void run() {
((LinphoneCallTest)call).state = targetState;
onCallStateChanged(call, call.getState(), "simulated delayed state change " + targetState);
}
}, millis);
}
protected final List<LinphoneCall> getInitialCalls() { protected final List<LinphoneCall> getInitialCalls() {
List<LinphoneCall> calls = new ArrayList<LinphoneCall>(); List<LinphoneCall> calls = new ArrayList<LinphoneCall>();
@ -105,7 +113,8 @@ public class TestConferenceActivity extends ConferenceActivity {
if (isInConference()) { if (isInConference()) {
leaveConference(); leaveConference();
} else { } else {
pauseCall(getCurrentCall()); LinphoneCall current = getCurrentCall();
if (current != null) pauseCall(current);
} }
changeState(call, State.StreamsRunning); changeState(call, State.StreamsRunning);
} }
@ -180,6 +189,7 @@ public class TestConferenceActivity extends ConferenceActivity {
} }
public void playDtmf(char number, int duration) {} public void playDtmf(char number, int duration) {}
public boolean resumeCall(LinphoneCall call) { public boolean resumeCall(LinphoneCall call) {
if (isInConference()) leaveConference();
pauseAllCalls(); pauseAllCalls();
changeState(call, State.StreamsRunning); changeState(call, State.StreamsRunning);
return true; return true;
@ -230,9 +240,12 @@ public class TestConferenceActivity extends ConferenceActivity {
} }
public void addAllToConference() { public void addAllToConference() {
for (LinphoneCall c : calls) { for (LinphoneCall c : calls) {
int stateId = c.getState().value(); final LinphoneCall.State state = c.getState();
boolean connectionEstablished = stateId == State.ID_STREAMS_RUNNING || stateId == State.ID_PAUSED || stateId == State.ID_PAUSED_BY_REMOTE; boolean connectionEstablished = state == State.StreamsRunning || state == State.Paused || state == State.PausedByRemote;
if (connectionEstablished) changeStateInConf(c, true); if (connectionEstablished) {
changeState(c, State.StreamsRunning);
changeStateInConf(c, true);
}
} }
enterConference(); enterConference();
} }
@ -241,6 +254,7 @@ public class TestConferenceActivity extends ConferenceActivity {
addAllToConference(); addAllToConference();
} else { } else {
boolean mergingActiveCall = call.equals(getCurrentCall()); boolean mergingActiveCall = call.equals(getCurrentCall());
changeState(call, State.StreamsRunning);
changeStateInConf(call, true); changeStateInConf(call, true);
if (mergingActiveCall) enterConference(); if (mergingActiveCall) enterConference();
} }
@ -278,9 +292,22 @@ public class TestConferenceActivity extends ConferenceActivity {
return new ArrayList<LinphoneCall>(calls); return new ArrayList<LinphoneCall>(calls);
} }
public void removeFromConference(LinphoneCall call) { public void removeFromConference(LinphoneCall call) {
changeState(call, State.StreamsRunning); changeStateInConf(call, false);
changeState(call, State.Paused);
} }
public void transferCall(LinphoneCall call, String referTo) {
terminateCall(call);
}
public void transferCallToAnother(LinphoneCall callToTransfer, LinphoneCall destination) {
if (!State.Paused.equals(callToTransfer.getState())) {
throw new RuntimeException("call to transfer should be paused first");
}
terminateCall(callToTransfer);
delayedCallEvent(destination, State.CallEnd, 3000);
}
public int getVideoDevice() {return 0;}
public void setDeviceRotation(int rotation) {}
public void setVideoDevice(int id) {}
} }
@ -338,6 +365,7 @@ public class TestConferenceActivity extends ConferenceActivity {
public boolean isEchoCancellationEnabled() {return false;} public boolean isEchoCancellationEnabled() {return false;}
public boolean isEchoLimiterEnabled() {return false;} public boolean isEchoLimiterEnabled() {return false;}
public boolean isInConference() { return inConf;} public boolean isInConference() { return inConf;}
public boolean cameraEnabled() {return false;}
} }