diff --git a/.classpath b/.classpath
index 902041fc9..c6e88a7fc 100644
--- a/.classpath
+++ b/.classpath
@@ -9,5 +9,6 @@
+
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3271c482f..8768ca55c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,8 +1,8 @@
-
+ android:versionCode="2000" android:versionName="2.0" android:installLocation="auto">
+
@@ -27,6 +27,7 @@
@@ -44,7 +45,7 @@
-
+
@@ -52,11 +53,10 @@
-
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:screenOrientation="portrait"
+ android:launchMode="singleTask">
@@ -65,154 +65,65 @@
+ android:launchMode="singleInstance"
+ android:screenOrientation="portrait">
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/build.xml b/build.xml
index 1e18ac78e..bc2747bbf 100644
--- a/build.xml
+++ b/build.xml
@@ -1189,7 +1189,7 @@
-
diff --git a/default.properties b/default.properties
deleted file mode 100644
index ac9e1a0b5..000000000
--- a/default.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "build.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-13
diff --git a/libs/android-support-v4.jar b/libs/android-support-v4.jar
new file mode 100644
index 000000000..1fbeba093
Binary files /dev/null and b/libs/android-support-v4.jar differ
diff --git a/res/anim/slide_in_bottom_to_top.xml b/res/anim/slide_in_bottom_to_top.xml
new file mode 100644
index 000000000..1cc55f9ab
--- /dev/null
+++ b/res/anim/slide_in_bottom_to_top.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/anim/slide_in_left_to_right.xml b/res/anim/slide_in_left_to_right.xml
new file mode 100644
index 000000000..490677824
--- /dev/null
+++ b/res/anim/slide_in_left_to_right.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/anim/slide_in_right_to_left.xml b/res/anim/slide_in_right_to_left.xml
new file mode 100644
index 000000000..bf15b1e13
--- /dev/null
+++ b/res/anim/slide_in_right_to_left.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/anim/slide_in_top_to_bottom.xml b/res/anim/slide_in_top_to_bottom.xml
new file mode 100644
index 000000000..6bb7ac339
--- /dev/null
+++ b/res/anim/slide_in_top_to_bottom.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/anim/slide_out_bottom_to_top.xml b/res/anim/slide_out_bottom_to_top.xml
new file mode 100644
index 000000000..5db6fd044
--- /dev/null
+++ b/res/anim/slide_out_bottom_to_top.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/anim/slide_out_left_to_right.xml b/res/anim/slide_out_left_to_right.xml
new file mode 100644
index 000000000..a18fc009b
--- /dev/null
+++ b/res/anim/slide_out_left_to_right.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/anim/slide_out_right_to_left.xml b/res/anim/slide_out_right_to_left.xml
new file mode 100644
index 000000000..4866f0a2d
--- /dev/null
+++ b/res/anim/slide_out_right_to_left.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/anim/slide_out_top_to_bottom.xml b/res/anim/slide_out_top_to_bottom.xml
new file mode 100644
index 000000000..ad6838797
--- /dev/null
+++ b/res/anim/slide_out_top_to_bottom.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png b/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png
deleted file mode 100644
index 7c4f40ea9..000000000
Binary files a/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png b/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png
deleted file mode 100644
index b9ec2374a..000000000
Binary files a/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png b/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png
deleted file mode 100644
index 2800cabeb..000000000
Binary files a/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png b/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png
deleted file mode 100644
index fd98571d3..000000000
Binary files a/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png b/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png
deleted file mode 100644
index 49ec1184f..000000000
Binary files a/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png b/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png
deleted file mode 100644
index ffc54339d..000000000
Binary files a/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_left_confirm_green.png b/res/drawable-hdpi/jog_tab_left_confirm_green.png
deleted file mode 100644
index 23acc95f1..000000000
Binary files a/res/drawable-hdpi/jog_tab_left_confirm_green.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_left_normal.png b/res/drawable-hdpi/jog_tab_left_normal.png
deleted file mode 100644
index 18216f946..000000000
Binary files a/res/drawable-hdpi/jog_tab_left_normal.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_left_pressed.png b/res/drawable-hdpi/jog_tab_left_pressed.png
deleted file mode 100644
index 86f49c685..000000000
Binary files a/res/drawable-hdpi/jog_tab_left_pressed.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_right_confirm_red.png b/res/drawable-hdpi/jog_tab_right_confirm_red.png
deleted file mode 100644
index bb0fa4754..000000000
Binary files a/res/drawable-hdpi/jog_tab_right_confirm_red.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_right_normal.png b/res/drawable-hdpi/jog_tab_right_normal.png
deleted file mode 100644
index 68545ef51..000000000
Binary files a/res/drawable-hdpi/jog_tab_right_normal.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_right_pressed.png b/res/drawable-hdpi/jog_tab_right_pressed.png
deleted file mode 100644
index 3d75c0d9b..000000000
Binary files a/res/drawable-hdpi/jog_tab_right_pressed.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_target_green.png b/res/drawable-hdpi/jog_tab_target_green.png
deleted file mode 100644
index 17f6b101e..000000000
Binary files a/res/drawable-hdpi/jog_tab_target_green.png and /dev/null differ
diff --git a/res/drawable-hdpi/jog_tab_target_red.png b/res/drawable-hdpi/jog_tab_target_red.png
deleted file mode 100644
index 8db20bb63..000000000
Binary files a/res/drawable-hdpi/jog_tab_target_red.png and /dev/null differ
diff --git a/res/drawable/.DS_Store b/res/drawable/.DS_Store
deleted file mode 100644
index 308abc851..000000000
Binary files a/res/drawable/.DS_Store and /dev/null differ
diff --git a/res/drawable/add_call.xml b/res/drawable/add_call.xml
new file mode 100644
index 000000000..b3589eb49
--- /dev/null
+++ b/res/drawable/add_call.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/res/drawable/add_call_default.png b/res/drawable/add_call_default.png
new file mode 100644
index 000000000..8dbce108c
Binary files /dev/null and b/res/drawable/add_call_default.png differ
diff --git a/res/drawable/add_call_more_default.png b/res/drawable/add_call_more_default.png
new file mode 100644
index 000000000..0932c749d
Binary files /dev/null and b/res/drawable/add_call_more_default.png differ
diff --git a/res/drawable/add_call_more_disable.png b/res/drawable/add_call_more_disable.png
new file mode 100644
index 000000000..caee628d0
Binary files /dev/null and b/res/drawable/add_call_more_disable.png differ
diff --git a/res/drawable/add_call_more_over.png b/res/drawable/add_call_more_over.png
new file mode 100644
index 000000000..09e5b9197
Binary files /dev/null and b/res/drawable/add_call_more_over.png differ
diff --git a/res/drawable/add_call_over.png b/res/drawable/add_call_over.png
new file mode 100644
index 000000000..50fefa47f
Binary files /dev/null and b/res/drawable/add_call_over.png differ
diff --git a/res/drawable/add_contact.xml b/res/drawable/add_contact.xml
new file mode 100644
index 000000000..c100ec00b
--- /dev/null
+++ b/res/drawable/add_contact.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/res/drawable/add_contact_default.png b/res/drawable/add_contact_default.png
new file mode 100644
index 000000000..5da115460
Binary files /dev/null and b/res/drawable/add_contact_default.png differ
diff --git a/res/drawable/add_contact_disabled.png b/res/drawable/add_contact_disabled.png
new file mode 100644
index 000000000..337a99e51
Binary files /dev/null and b/res/drawable/add_contact_disabled.png differ
diff --git a/res/drawable/add_contact_over.png b/res/drawable/add_contact_over.png
new file mode 100644
index 000000000..0230d7e76
Binary files /dev/null and b/res/drawable/add_contact_over.png differ
diff --git a/res/drawable/all_contacts.xml b/res/drawable/all_contacts.xml
new file mode 100644
index 000000000..6746f8f0f
--- /dev/null
+++ b/res/drawable/all_contacts.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/all_default.png b/res/drawable/all_default.png
new file mode 100644
index 000000000..18e7eebd4
Binary files /dev/null and b/res/drawable/all_default.png differ
diff --git a/res/drawable/all_selected.png b/res/drawable/all_selected.png
new file mode 100644
index 000000000..d062ce11c
Binary files /dev/null and b/res/drawable/all_selected.png differ
diff --git a/res/drawable/background.png b/res/drawable/background.png
new file mode 100644
index 000000000..062a1eca5
Binary files /dev/null and b/res/drawable/background.png differ
diff --git a/res/drawable/backspace.xml b/res/drawable/backspace.xml
new file mode 100644
index 000000000..6f2a75a42
--- /dev/null
+++ b/res/drawable/backspace.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/backspace_default.png b/res/drawable/backspace_default.png
new file mode 100644
index 000000000..b19ba4fa1
Binary files /dev/null and b/res/drawable/backspace_default.png differ
diff --git a/res/drawable/backspace_over.png b/res/drawable/backspace_over.png
new file mode 100644
index 000000000..abd0e13a6
Binary files /dev/null and b/res/drawable/backspace_over.png differ
diff --git a/res/drawable/button.xml b/res/drawable/button.xml
new file mode 100644
index 000000000..ab6a95baa
--- /dev/null
+++ b/res/drawable/button.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/button_background_default.png b/res/drawable/button_background_default.png
new file mode 100644
index 000000000..31efad8aa
Binary files /dev/null and b/res/drawable/button_background_default.png differ
diff --git a/res/drawable/button_background_over.png b/res/drawable/button_background_over.png
new file mode 100644
index 000000000..44813921c
Binary files /dev/null and b/res/drawable/button_background_over.png differ
diff --git a/res/drawable/call.xml b/res/drawable/call.xml
new file mode 100644
index 000000000..e9355926a
--- /dev/null
+++ b/res/drawable/call.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/call_answer.xml b/res/drawable/call_answer.xml
new file mode 100644
index 000000000..a81d47745
--- /dev/null
+++ b/res/drawable/call_answer.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/call_answer_default.png b/res/drawable/call_answer_default.png
new file mode 100644
index 000000000..56cd9d677
Binary files /dev/null and b/res/drawable/call_answer_default.png differ
diff --git a/res/drawable/call_answer_over.png b/res/drawable/call_answer_over.png
new file mode 100644
index 000000000..ea860d42c
Binary files /dev/null and b/res/drawable/call_answer_over.png differ
diff --git a/res/drawable/call_default.png b/res/drawable/call_default.png
new file mode 100644
index 000000000..fc2792247
Binary files /dev/null and b/res/drawable/call_default.png differ
diff --git a/res/drawable/call_over.png b/res/drawable/call_over.png
new file mode 100644
index 000000000..9cbf18c60
Binary files /dev/null and b/res/drawable/call_over.png differ
diff --git a/res/drawable/call_quality_indicator_0.png b/res/drawable/call_quality_indicator_0.png
new file mode 100644
index 000000000..7bdaf40ab
Binary files /dev/null and b/res/drawable/call_quality_indicator_0.png differ
diff --git a/res/drawable/call_quality_indicator_1.png b/res/drawable/call_quality_indicator_1.png
new file mode 100644
index 000000000..2cca9b39c
Binary files /dev/null and b/res/drawable/call_quality_indicator_1.png differ
diff --git a/res/drawable/call_quality_indicator_2.png b/res/drawable/call_quality_indicator_2.png
new file mode 100644
index 000000000..adab949fc
Binary files /dev/null and b/res/drawable/call_quality_indicator_2.png differ
diff --git a/res/drawable/call_quality_indicator_3.png b/res/drawable/call_quality_indicator_3.png
new file mode 100644
index 000000000..91118ff60
Binary files /dev/null and b/res/drawable/call_quality_indicator_3.png differ
diff --git a/res/drawable/call_refused_icon.png b/res/drawable/call_refused_icon.png
new file mode 100644
index 000000000..084515cfe
Binary files /dev/null and b/res/drawable/call_refused_icon.png differ
diff --git a/res/drawable/call_refused_icon_over.png b/res/drawable/call_refused_icon_over.png
new file mode 100644
index 000000000..c821dc13b
Binary files /dev/null and b/res/drawable/call_refused_icon_over.png differ
diff --git a/res/drawable/call_status_incoming.png b/res/drawable/call_status_incoming.png
new file mode 100644
index 000000000..2ce5c676e
Binary files /dev/null and b/res/drawable/call_status_incoming.png differ
diff --git a/res/drawable/call_status_missed.png b/res/drawable/call_status_missed.png
new file mode 100644
index 000000000..426dee899
Binary files /dev/null and b/res/drawable/call_status_missed.png differ
diff --git a/res/drawable/call_status_outgoing.png b/res/drawable/call_status_outgoing.png
new file mode 100644
index 000000000..645875ce1
Binary files /dev/null and b/res/drawable/call_status_outgoing.png differ
diff --git a/res/drawable/cancel.xml b/res/drawable/cancel.xml
new file mode 100644
index 000000000..b78cf842d
--- /dev/null
+++ b/res/drawable/cancel.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/cancel_white_bg_default.png b/res/drawable/cancel_white_bg_default.png
new file mode 100644
index 000000000..d7088080a
Binary files /dev/null and b/res/drawable/cancel_white_bg_default.png differ
diff --git a/res/drawable/cancel_white_bg_disabled.png b/res/drawable/cancel_white_bg_disabled.png
new file mode 100644
index 000000000..d6e641fa5
Binary files /dev/null and b/res/drawable/cancel_white_bg_disabled.png differ
diff --git a/res/drawable/cancel_white_bg_over.png b/res/drawable/cancel_white_bg_over.png
new file mode 100644
index 000000000..d06321994
Binary files /dev/null and b/res/drawable/cancel_white_bg_over.png differ
diff --git a/res/drawable/cell_background.png b/res/drawable/cell_background.png
new file mode 100644
index 000000000..5ca0934fb
Binary files /dev/null and b/res/drawable/cell_background.png differ
diff --git a/res/drawable/chat.xml b/res/drawable/chat.xml
new file mode 100644
index 000000000..a7a0da6b3
--- /dev/null
+++ b/res/drawable/chat.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/chat_bubble_incoming.9.png b/res/drawable/chat_bubble_incoming.9.png
new file mode 100644
index 000000000..68ef2b302
Binary files /dev/null and b/res/drawable/chat_bubble_incoming.9.png differ
diff --git a/res/drawable/chat_bubble_outgoing.9.png b/res/drawable/chat_bubble_outgoing.9.png
new file mode 100644
index 000000000..1aa640f8c
Binary files /dev/null and b/res/drawable/chat_bubble_outgoing.9.png differ
diff --git a/res/drawable/chat_default.png b/res/drawable/chat_default.png
new file mode 100644
index 000000000..5e9716cc8
Binary files /dev/null and b/res/drawable/chat_default.png differ
diff --git a/res/drawable/chat_edit.xml b/res/drawable/chat_edit.xml
new file mode 100644
index 000000000..8722d6690
--- /dev/null
+++ b/res/drawable/chat_edit.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/chat_edit_default.png b/res/drawable/chat_edit_default.png
new file mode 100644
index 000000000..428ce5df8
Binary files /dev/null and b/res/drawable/chat_edit_default.png differ
diff --git a/res/drawable/chat_edit_over.png b/res/drawable/chat_edit_over.png
new file mode 100644
index 000000000..62c0a4c34
Binary files /dev/null and b/res/drawable/chat_edit_over.png differ
diff --git a/res/drawable/chat_icon_default.png b/res/drawable/chat_icon_default.png
new file mode 100644
index 000000000..7a26c20eb
Binary files /dev/null and b/res/drawable/chat_icon_default.png differ
diff --git a/res/drawable/chat_icon_over.png b/res/drawable/chat_icon_over.png
new file mode 100644
index 000000000..7da46015c
Binary files /dev/null and b/res/drawable/chat_icon_over.png differ
diff --git a/res/drawable/chat_message_background.png b/res/drawable/chat_message_background.png
new file mode 100644
index 000000000..17a1bee8d
Binary files /dev/null and b/res/drawable/chat_message_background.png differ
diff --git a/res/drawable/chat_new.xml b/res/drawable/chat_new.xml
new file mode 100644
index 000000000..e42e5819c
--- /dev/null
+++ b/res/drawable/chat_new.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/chat_new_default.png b/res/drawable/chat_new_default.png
new file mode 100644
index 000000000..053723d22
Binary files /dev/null and b/res/drawable/chat_new_default.png differ
diff --git a/res/drawable/chat_new_over.png b/res/drawable/chat_new_over.png
new file mode 100644
index 000000000..34ffdf83f
Binary files /dev/null and b/res/drawable/chat_new_over.png differ
diff --git a/res/drawable/chat_ok.xml b/res/drawable/chat_ok.xml
new file mode 100644
index 000000000..3b5a53732
--- /dev/null
+++ b/res/drawable/chat_ok.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/chat_ok_default.png b/res/drawable/chat_ok_default.png
new file mode 100644
index 000000000..0c49ac3d5
Binary files /dev/null and b/res/drawable/chat_ok_default.png differ
diff --git a/res/drawable/chat_ok_over.png b/res/drawable/chat_ok_over.png
new file mode 100644
index 000000000..4fe6248f8
Binary files /dev/null and b/res/drawable/chat_ok_over.png differ
diff --git a/res/drawable/chat_over.png b/res/drawable/chat_over.png
new file mode 100644
index 000000000..1d945dbfd
Binary files /dev/null and b/res/drawable/chat_over.png differ
diff --git a/res/drawable/chat_selected.png b/res/drawable/chat_selected.png
new file mode 100644
index 000000000..2638c0c10
Binary files /dev/null and b/res/drawable/chat_selected.png differ
diff --git a/res/drawable/chat_send_message.xml b/res/drawable/chat_send_message.xml
new file mode 100644
index 000000000..afcfe5074
--- /dev/null
+++ b/res/drawable/chat_send_message.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/chat_send_message_default.png b/res/drawable/chat_send_message_default.png
new file mode 100644
index 000000000..1bee48a2f
Binary files /dev/null and b/res/drawable/chat_send_message_default.png differ
diff --git a/res/drawable/chat_send_message_over.png b/res/drawable/chat_send_message_over.png
new file mode 100644
index 000000000..a130fe1bf
Binary files /dev/null and b/res/drawable/chat_send_message_over.png differ
diff --git a/res/drawable/clavier_bg.xml b/res/drawable/clavier_bg.xml
deleted file mode 100644
index 4b3009000..000000000
--- a/res/drawable/clavier_bg.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/res/drawable/clavier_bg_darkgrey.png b/res/drawable/clavier_bg_darkgrey.png
deleted file mode 100644
index e93271086..000000000
Binary files a/res/drawable/clavier_bg_darkgrey.png and /dev/null differ
diff --git a/res/drawable/clavier_bg_grey.png b/res/drawable/clavier_bg_grey.png
deleted file mode 100644
index 151877f97..000000000
Binary files a/res/drawable/clavier_bg_grey.png and /dev/null differ
diff --git a/res/drawable/clavier_bg_orange.png b/res/drawable/clavier_bg_orange.png
deleted file mode 100644
index fe8fef617..000000000
Binary files a/res/drawable/clavier_bg_orange.png and /dev/null differ
diff --git a/res/drawable/conf_callee_active_bg.xml b/res/drawable/conf_callee_active_bg.xml
deleted file mode 100644
index 662710e79..000000000
--- a/res/drawable/conf_callee_active_bg.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_bg.xml b/res/drawable/conf_callee_bg.xml
deleted file mode 100644
index 34c4f8687..000000000
--- a/res/drawable/conf_callee_bg.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_incoming_bg.xml b/res/drawable/conf_callee_incoming_bg.xml
deleted file mode 100644
index 65ed06b42..000000000
--- a/res/drawable/conf_callee_incoming_bg.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_inconf_bg.xml b/res/drawable/conf_callee_inconf_bg.xml
deleted file mode 100644
index ada123c15..000000000
--- a/res/drawable/conf_callee_inconf_bg.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_pressed_bg.xml b/res/drawable/conf_callee_pressed_bg.xml
deleted file mode 100644
index 31cfd4a6f..000000000
--- a/res/drawable/conf_callee_pressed_bg.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_selected_bg.xml b/res/drawable/conf_callee_selected_bg.xml
deleted file mode 100644
index d98b22f5a..000000000
--- a/res/drawable/conf_callee_selected_bg.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_selector_active.xml b/res/drawable/conf_callee_selector_active.xml
deleted file mode 100644
index cb64a4a1e..000000000
--- a/res/drawable/conf_callee_selector_active.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_selector_incoming.xml b/res/drawable/conf_callee_selector_incoming.xml
deleted file mode 100644
index b7e045d00..000000000
--- a/res/drawable/conf_callee_selector_incoming.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_selector_inconf.xml b/res/drawable/conf_callee_selector_inconf.xml
deleted file mode 100644
index 85e3ea5ff..000000000
--- a/res/drawable/conf_callee_selector_inconf.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/res/drawable/conf_callee_selector_normal.xml b/res/drawable/conf_callee_selector_normal.xml
deleted file mode 100644
index 2da1f36ac..000000000
--- a/res/drawable/conf_callee_selector_normal.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/res/drawable/conf_details.png b/res/drawable/conf_details.png
deleted file mode 100644
index 7168af580..000000000
Binary files a/res/drawable/conf_details.png and /dev/null differ
diff --git a/res/drawable/conf_maybe_secured.png b/res/drawable/conf_maybe_secured.png
deleted file mode 100644
index 106cf427d..000000000
Binary files a/res/drawable/conf_maybe_secured.png and /dev/null differ
diff --git a/res/drawable/conf_merge.png b/res/drawable/conf_merge.png
deleted file mode 100644
index 2f76509b5..000000000
Binary files a/res/drawable/conf_merge.png and /dev/null differ
diff --git a/res/drawable/conf_merge_all.png b/res/drawable/conf_merge_all.png
deleted file mode 100644
index 66626fe71..000000000
Binary files a/res/drawable/conf_merge_all.png and /dev/null differ
diff --git a/res/drawable/conf_not_secured.png b/res/drawable/conf_not_secured.png
deleted file mode 100644
index 1381f4d17..000000000
Binary files a/res/drawable/conf_not_secured.png and /dev/null differ
diff --git a/res/drawable/conf_pause.png b/res/drawable/conf_pause.png
deleted file mode 100644
index 9ab5bae92..000000000
Binary files a/res/drawable/conf_pause.png and /dev/null differ
diff --git a/res/drawable/conf_permute.png b/res/drawable/conf_permute.png
deleted file mode 100644
index 225b8bf7d..000000000
Binary files a/res/drawable/conf_permute.png and /dev/null differ
diff --git a/res/drawable/conf_remove.png b/res/drawable/conf_remove.png
deleted file mode 100644
index 7570cc599..000000000
Binary files a/res/drawable/conf_remove.png and /dev/null differ
diff --git a/res/drawable/conf_resume.png b/res/drawable/conf_resume.png
deleted file mode 100644
index b8a2d50cd..000000000
Binary files a/res/drawable/conf_resume.png and /dev/null differ
diff --git a/res/drawable/conf_secured.png b/res/drawable/conf_secured.png
deleted file mode 100644
index 61042339f..000000000
Binary files a/res/drawable/conf_secured.png and /dev/null differ
diff --git a/res/drawable/conf_speaking.png b/res/drawable/conf_speaking.png
deleted file mode 100644
index 2324d81c3..000000000
Binary files a/res/drawable/conf_speaking.png and /dev/null differ
diff --git a/res/drawable/conf_status_inconf.png b/res/drawable/conf_status_inconf.png
deleted file mode 100644
index 3f89fb3fb..000000000
Binary files a/res/drawable/conf_status_inconf.png and /dev/null differ
diff --git a/res/drawable/conf_terminate.png b/res/drawable/conf_terminate.png
deleted file mode 100644
index 0a11c639e..000000000
Binary files a/res/drawable/conf_terminate.png and /dev/null differ
diff --git a/res/drawable/conf_transfer.png b/res/drawable/conf_transfer.png
deleted file mode 100644
index d539cd241..000000000
Binary files a/res/drawable/conf_transfer.png and /dev/null differ
diff --git a/res/drawable/contact_orange.png b/res/drawable/contact_orange.png
deleted file mode 100644
index 53ba07ed8..000000000
Binary files a/res/drawable/contact_orange.png and /dev/null differ
diff --git a/res/drawable/contacts.xml b/res/drawable/contacts.xml
new file mode 100644
index 000000000..52818fa7d
--- /dev/null
+++ b/res/drawable/contacts.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/contacts_default.png b/res/drawable/contacts_default.png
new file mode 100644
index 000000000..88039d6c5
Binary files /dev/null and b/res/drawable/contacts_default.png differ
diff --git a/res/drawable/contacts_over.png b/res/drawable/contacts_over.png
new file mode 100644
index 000000000..1cf7fd7ab
Binary files /dev/null and b/res/drawable/contacts_over.png differ
diff --git a/res/drawable/contacts_selected.png b/res/drawable/contacts_selected.png
new file mode 100644
index 000000000..baf14ed3e
Binary files /dev/null and b/res/drawable/contacts_selected.png differ
diff --git a/res/drawable/delete_default.png b/res/drawable/delete_default.png
new file mode 100644
index 000000000..8c1843de8
Binary files /dev/null and b/res/drawable/delete_default.png differ
diff --git a/res/drawable/delete_over.png b/res/drawable/delete_over.png
new file mode 100644
index 000000000..bc01f8f5d
Binary files /dev/null and b/res/drawable/delete_over.png differ
diff --git a/res/drawable/dialer.xml b/res/drawable/dialer.xml
new file mode 100644
index 000000000..345f9eceb
--- /dev/null
+++ b/res/drawable/dialer.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/dialer_address_background.png b/res/drawable/dialer_address_background.png
new file mode 100644
index 000000000..0751263e1
Binary files /dev/null and b/res/drawable/dialer_address_background.png differ
diff --git a/res/drawable/dialer_alt.xml b/res/drawable/dialer_alt.xml
new file mode 100644
index 000000000..d18fa3037
--- /dev/null
+++ b/res/drawable/dialer_alt.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/dialer_alt_default.png b/res/drawable/dialer_alt_default.png
new file mode 100644
index 000000000..43d512c04
Binary files /dev/null and b/res/drawable/dialer_alt_default.png differ
diff --git a/res/drawable/dialer_alt_over.png b/res/drawable/dialer_alt_over.png
new file mode 100644
index 000000000..28567955d
Binary files /dev/null and b/res/drawable/dialer_alt_over.png differ
diff --git a/res/drawable/dialer_default.png b/res/drawable/dialer_default.png
new file mode 100644
index 000000000..b23fcbb41
Binary files /dev/null and b/res/drawable/dialer_default.png differ
diff --git a/res/drawable/dialer_orange.png b/res/drawable/dialer_orange.png
deleted file mode 100644
index 2d715eac0..000000000
Binary files a/res/drawable/dialer_orange.png and /dev/null differ
diff --git a/res/drawable/dialer_over.png b/res/drawable/dialer_over.png
new file mode 100644
index 000000000..3727c5fba
Binary files /dev/null and b/res/drawable/dialer_over.png differ
diff --git a/res/drawable/dialer_selected.png b/res/drawable/dialer_selected.png
new file mode 100644
index 000000000..5883398d2
Binary files /dev/null and b/res/drawable/dialer_selected.png differ
diff --git a/res/drawable/hangup.xml b/res/drawable/hangup.xml
new file mode 100644
index 000000000..7faa23180
--- /dev/null
+++ b/res/drawable/hangup.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/hangup_default.png b/res/drawable/hangup_default.png
new file mode 100644
index 000000000..c84ea15b2
Binary files /dev/null and b/res/drawable/hangup_default.png differ
diff --git a/res/drawable/hangup_over.png b/res/drawable/hangup_over.png
new file mode 100644
index 000000000..2c95c5c1a
Binary files /dev/null and b/res/drawable/hangup_over.png differ
diff --git a/res/drawable/history.xml b/res/drawable/history.xml
new file mode 100644
index 000000000..6f32df31c
--- /dev/null
+++ b/res/drawable/history.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/history_all.xml b/res/drawable/history_all.xml
new file mode 100644
index 000000000..2ce87fc7b
--- /dev/null
+++ b/res/drawable/history_all.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/history_all_default.png b/res/drawable/history_all_default.png
new file mode 100644
index 000000000..fe9f61f2f
Binary files /dev/null and b/res/drawable/history_all_default.png differ
diff --git a/res/drawable/history_all_selected.png b/res/drawable/history_all_selected.png
new file mode 100644
index 000000000..9790cc945
Binary files /dev/null and b/res/drawable/history_all_selected.png differ
diff --git a/res/drawable/history_default.png b/res/drawable/history_default.png
new file mode 100644
index 000000000..866a25a77
Binary files /dev/null and b/res/drawable/history_default.png differ
diff --git a/res/drawable/history_edit.xml b/res/drawable/history_edit.xml
new file mode 100644
index 000000000..a2108f74b
--- /dev/null
+++ b/res/drawable/history_edit.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/history_edit_default.png b/res/drawable/history_edit_default.png
new file mode 100644
index 000000000..bfb27dedc
Binary files /dev/null and b/res/drawable/history_edit_default.png differ
diff --git a/res/drawable/history_edit_over.png b/res/drawable/history_edit_over.png
new file mode 100644
index 000000000..679ae9f8b
Binary files /dev/null and b/res/drawable/history_edit_over.png differ
diff --git a/res/drawable/history_missed.xml b/res/drawable/history_missed.xml
new file mode 100644
index 000000000..fef83cb22
--- /dev/null
+++ b/res/drawable/history_missed.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/res/drawable/history_missed_default.png b/res/drawable/history_missed_default.png
new file mode 100644
index 000000000..0f2f99b4e
Binary files /dev/null and b/res/drawable/history_missed_default.png differ
diff --git a/res/drawable/history_missed_selected.png b/res/drawable/history_missed_selected.png
new file mode 100644
index 000000000..cb413d997
Binary files /dev/null and b/res/drawable/history_missed_selected.png differ
diff --git a/res/drawable/history_orange.png b/res/drawable/history_orange.png
deleted file mode 100644
index dc9bbf60a..000000000
Binary files a/res/drawable/history_orange.png and /dev/null differ
diff --git a/res/drawable/history_over.png b/res/drawable/history_over.png
new file mode 100644
index 000000000..fbcaec907
Binary files /dev/null and b/res/drawable/history_over.png differ
diff --git a/res/drawable/history_selected.png b/res/drawable/history_selected.png
new file mode 100644
index 000000000..b672b21f3
Binary files /dev/null and b/res/drawable/history_selected.png differ
diff --git a/res/drawable/in_call.png b/res/drawable/in_call.png
deleted file mode 100644
index d48369e6a..000000000
Binary files a/res/drawable/in_call.png and /dev/null differ
diff --git a/res/drawable/in_call_mini.png b/res/drawable/in_call_mini.png
deleted file mode 100644
index e307d23e3..000000000
Binary files a/res/drawable/in_call_mini.png and /dev/null differ
diff --git a/res/drawable/incall_add.png b/res/drawable/incall_add.png
deleted file mode 100755
index c1526d8ba..000000000
Binary files a/res/drawable/incall_add.png and /dev/null differ
diff --git a/res/drawable/incall_add_small.png b/res/drawable/incall_add_small.png
deleted file mode 100755
index 9913cc582..000000000
Binary files a/res/drawable/incall_add_small.png and /dev/null differ
diff --git a/res/drawable/incall_back.png b/res/drawable/incall_back.png
deleted file mode 100755
index 685c72cbb..000000000
Binary files a/res/drawable/incall_back.png and /dev/null differ
diff --git a/res/drawable/incall_dialpad.png b/res/drawable/incall_dialpad.png
deleted file mode 100755
index 3d2d9495b..000000000
Binary files a/res/drawable/incall_dialpad.png and /dev/null differ
diff --git a/res/drawable/incall_merge.png b/res/drawable/incall_merge.png
deleted file mode 100755
index 70ed3cbc7..000000000
Binary files a/res/drawable/incall_merge.png and /dev/null differ
diff --git a/res/drawable/incall_micro.png b/res/drawable/incall_micro.png
deleted file mode 100755
index 7c694fbff..000000000
Binary files a/res/drawable/incall_micro.png and /dev/null differ
diff --git a/res/drawable/incall_micro_inverse.png b/res/drawable/incall_micro_inverse.png
deleted file mode 100755
index dc38d85a6..000000000
Binary files a/res/drawable/incall_micro_inverse.png and /dev/null differ
diff --git a/res/drawable/incall_pause.png b/res/drawable/incall_pause.png
deleted file mode 100755
index 37d96580b..000000000
Binary files a/res/drawable/incall_pause.png and /dev/null differ
diff --git a/res/drawable/incall_pause_inverse.png b/res/drawable/incall_pause_inverse.png
deleted file mode 100755
index 0b46f283c..000000000
Binary files a/res/drawable/incall_pause_inverse.png and /dev/null differ
diff --git a/res/drawable/incall_speaker.png b/res/drawable/incall_speaker.png
deleted file mode 100755
index 95d132189..000000000
Binary files a/res/drawable/incall_speaker.png and /dev/null differ
diff --git a/res/drawable/incall_speaker_inverse.png b/res/drawable/incall_speaker_inverse.png
deleted file mode 100755
index e343dba73..000000000
Binary files a/res/drawable/incall_speaker_inverse.png and /dev/null differ
diff --git a/res/drawable/jog_tab_bar_left_answer.xml b/res/drawable/jog_tab_bar_left_answer.xml
deleted file mode 100644
index 32ce3dcda..000000000
--- a/res/drawable/jog_tab_bar_left_answer.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/drawable/jog_tab_bar_left_end_confirm_green.9.png b/res/drawable/jog_tab_bar_left_end_confirm_green.9.png
deleted file mode 100644
index e8be7bf37..000000000
Binary files a/res/drawable/jog_tab_bar_left_end_confirm_green.9.png and /dev/null differ
diff --git a/res/drawable/jog_tab_bar_left_end_normal.9.png b/res/drawable/jog_tab_bar_left_end_normal.9.png
deleted file mode 100644
index 747745378..000000000
Binary files a/res/drawable/jog_tab_bar_left_end_normal.9.png and /dev/null differ
diff --git a/res/drawable/jog_tab_bar_left_end_pressed.9.png b/res/drawable/jog_tab_bar_left_end_pressed.9.png
deleted file mode 100644
index c79a35cf3..000000000
Binary files a/res/drawable/jog_tab_bar_left_end_pressed.9.png and /dev/null differ
diff --git a/res/drawable/jog_tab_bar_right_decline.xml b/res/drawable/jog_tab_bar_right_decline.xml
deleted file mode 100644
index 83183ac1b..000000000
--- a/res/drawable/jog_tab_bar_right_decline.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/drawable/jog_tab_bar_right_end_confirm_red.9.png b/res/drawable/jog_tab_bar_right_end_confirm_red.9.png
deleted file mode 100644
index 0242a42b5..000000000
Binary files a/res/drawable/jog_tab_bar_right_end_confirm_red.9.png and /dev/null differ
diff --git a/res/drawable/jog_tab_bar_right_end_normal.9.png b/res/drawable/jog_tab_bar_right_end_normal.9.png
deleted file mode 100644
index 2e6ca2ebf..000000000
Binary files a/res/drawable/jog_tab_bar_right_end_normal.9.png and /dev/null differ
diff --git a/res/drawable/jog_tab_bar_right_end_pressed.9.png b/res/drawable/jog_tab_bar_right_end_pressed.9.png
deleted file mode 100644
index 8bdfd8406..000000000
Binary files a/res/drawable/jog_tab_bar_right_end_pressed.9.png and /dev/null differ
diff --git a/res/drawable/jog_tab_left_answer.xml b/res/drawable/jog_tab_left_answer.xml
deleted file mode 100644
index 18ec7fa15..000000000
--- a/res/drawable/jog_tab_left_answer.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/drawable/jog_tab_left_confirm_green.png b/res/drawable/jog_tab_left_confirm_green.png
deleted file mode 100755
index 829b1462d..000000000
Binary files a/res/drawable/jog_tab_left_confirm_green.png and /dev/null differ
diff --git a/res/drawable/jog_tab_left_normal.png b/res/drawable/jog_tab_left_normal.png
deleted file mode 100755
index eb91e97ea..000000000
Binary files a/res/drawable/jog_tab_left_normal.png and /dev/null differ
diff --git a/res/drawable/jog_tab_left_pressed.png b/res/drawable/jog_tab_left_pressed.png
deleted file mode 100755
index 995199292..000000000
Binary files a/res/drawable/jog_tab_left_pressed.png and /dev/null differ
diff --git a/res/drawable/jog_tab_right_confirm_red.png b/res/drawable/jog_tab_right_confirm_red.png
deleted file mode 100644
index 2e1e105c6..000000000
Binary files a/res/drawable/jog_tab_right_confirm_red.png and /dev/null differ
diff --git a/res/drawable/jog_tab_right_decline.xml b/res/drawable/jog_tab_right_decline.xml
deleted file mode 100644
index a3bca5e92..000000000
--- a/res/drawable/jog_tab_right_decline.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/drawable/jog_tab_right_normal.png b/res/drawable/jog_tab_right_normal.png
deleted file mode 100755
index f2113f26e..000000000
Binary files a/res/drawable/jog_tab_right_normal.png and /dev/null differ
diff --git a/res/drawable/jog_tab_right_pressed.png b/res/drawable/jog_tab_right_pressed.png
deleted file mode 100755
index 65cd51ea6..000000000
Binary files a/res/drawable/jog_tab_right_pressed.png and /dev/null differ
diff --git a/res/drawable/jog_tab_target_green.png b/res/drawable/jog_tab_target_green.png
deleted file mode 100644
index 188f3cc83..000000000
Binary files a/res/drawable/jog_tab_target_green.png and /dev/null differ
diff --git a/res/drawable/jog_tab_target_red.png b/res/drawable/jog_tab_target_red.png
deleted file mode 100644
index a36394dc5..000000000
Binary files a/res/drawable/jog_tab_target_red.png and /dev/null differ
diff --git a/res/drawable/led_connected.png b/res/drawable/led_connected.png
new file mode 100644
index 000000000..e788e2b07
Binary files /dev/null and b/res/drawable/led_connected.png differ
diff --git a/res/drawable/led_disconnected.png b/res/drawable/led_disconnected.png
new file mode 100644
index 000000000..11455fb1b
Binary files /dev/null and b/res/drawable/led_disconnected.png differ
diff --git a/res/drawable/led_error.png b/res/drawable/led_error.png
new file mode 100644
index 000000000..e7617832b
Binary files /dev/null and b/res/drawable/led_error.png differ
diff --git a/res/drawable/led_inprogress.png b/res/drawable/led_inprogress.png
new file mode 100644
index 000000000..d2fe9da56
Binary files /dev/null and b/res/drawable/led_inprogress.png differ
diff --git a/res/drawable/linphone_contacts.xml b/res/drawable/linphone_contacts.xml
new file mode 100644
index 000000000..ba9480ade
--- /dev/null
+++ b/res/drawable/linphone_contacts.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/linphone_default.png b/res/drawable/linphone_default.png
new file mode 100644
index 000000000..9d240afeb
Binary files /dev/null and b/res/drawable/linphone_default.png differ
diff --git a/res/drawable/linphone_selected.png b/res/drawable/linphone_selected.png
new file mode 100644
index 000000000..0a75d15f0
Binary files /dev/null and b/res/drawable/linphone_selected.png differ
diff --git a/res/drawable/list_delete.xml b/res/drawable/list_delete.xml
new file mode 100644
index 000000000..e8c034ea1
--- /dev/null
+++ b/res/drawable/list_delete.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/res/drawable/list_delete_default.png b/res/drawable/list_delete_default.png
new file mode 100644
index 000000000..ef1ae410e
Binary files /dev/null and b/res/drawable/list_delete_default.png differ
diff --git a/res/drawable/list_delete_over.png b/res/drawable/list_delete_over.png
new file mode 100644
index 000000000..ec9522b3b
Binary files /dev/null and b/res/drawable/list_delete_over.png differ
diff --git a/res/drawable/list_detail.xml b/res/drawable/list_detail.xml
new file mode 100644
index 000000000..275fbd50d
--- /dev/null
+++ b/res/drawable/list_detail.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/res/drawable/list_detail_default.png b/res/drawable/list_detail_default.png
new file mode 100644
index 000000000..a4856294d
Binary files /dev/null and b/res/drawable/list_detail_default.png differ
diff --git a/res/drawable/list_detail_over.png b/res/drawable/list_detail_over.png
new file mode 100644
index 000000000..9cecd5e59
Binary files /dev/null and b/res/drawable/list_detail_over.png differ
diff --git a/res/drawable/mic_active.png b/res/drawable/mic_active.png
deleted file mode 100644
index 662526993..000000000
Binary files a/res/drawable/mic_active.png and /dev/null differ
diff --git a/res/drawable/mic_muted.png b/res/drawable/mic_muted.png
deleted file mode 100644
index f813691fc..000000000
Binary files a/res/drawable/mic_muted.png and /dev/null differ
diff --git a/res/drawable/micro_off.xml b/res/drawable/micro_off.xml
new file mode 100644
index 000000000..8a260ceaf
--- /dev/null
+++ b/res/drawable/micro_off.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/micro_off_default.png b/res/drawable/micro_off_default.png
new file mode 100644
index 000000000..2ec3be550
Binary files /dev/null and b/res/drawable/micro_off_default.png differ
diff --git a/res/drawable/micro_off_disabled.png b/res/drawable/micro_off_disabled.png
new file mode 100644
index 000000000..39f55197e
Binary files /dev/null and b/res/drawable/micro_off_disabled.png differ
diff --git a/res/drawable/micro_off_over.png b/res/drawable/micro_off_over.png
new file mode 100644
index 000000000..7c898d75d
Binary files /dev/null and b/res/drawable/micro_off_over.png differ
diff --git a/res/drawable/micro_on.xml b/res/drawable/micro_on.xml
new file mode 100644
index 000000000..396c876b4
--- /dev/null
+++ b/res/drawable/micro_on.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/micro_on_default.png b/res/drawable/micro_on_default.png
new file mode 100644
index 000000000..ca63b44ff
Binary files /dev/null and b/res/drawable/micro_on_default.png differ
diff --git a/res/drawable/micro_on_disabled.png b/res/drawable/micro_on_disabled.png
new file mode 100644
index 000000000..87fee6aa1
Binary files /dev/null and b/res/drawable/micro_on_disabled.png differ
diff --git a/res/drawable/micro_on_over.png b/res/drawable/micro_on_over.png
new file mode 100644
index 000000000..fd9d00a84
Binary files /dev/null and b/res/drawable/micro_on_over.png differ
diff --git a/res/drawable/mini_stopcall_red.png b/res/drawable/mini_stopcall_red.png
deleted file mode 100644
index fcf26c8bd..000000000
Binary files a/res/drawable/mini_stopcall_red.png and /dev/null differ
diff --git a/res/drawable/missed_calls_bg.xml b/res/drawable/missed_calls_bg.xml
new file mode 100644
index 000000000..e165bb056
--- /dev/null
+++ b/res/drawable/missed_calls_bg.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/new_contact.xml b/res/drawable/new_contact.xml
new file mode 100644
index 000000000..7989160af
--- /dev/null
+++ b/res/drawable/new_contact.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/new_contact_default.png b/res/drawable/new_contact_default.png
new file mode 100644
index 000000000..8498a06a0
Binary files /dev/null and b/res/drawable/new_contact_default.png differ
diff --git a/res/drawable/new_contact_over.png b/res/drawable/new_contact_over.png
new file mode 100644
index 000000000..71b833359
Binary files /dev/null and b/res/drawable/new_contact_over.png differ
diff --git a/res/drawable/numpad.png b/res/drawable/numpad.png
deleted file mode 100644
index f3965ef43..000000000
Binary files a/res/drawable/numpad.png and /dev/null differ
diff --git a/res/drawable/numpad_big.png b/res/drawable/numpad_big.png
deleted file mode 100644
index 2f1706869..000000000
Binary files a/res/drawable/numpad_big.png and /dev/null differ
diff --git a/res/drawable/numpad_eight.xml b/res/drawable/numpad_eight.xml
new file mode 100644
index 000000000..9c6ece841
--- /dev/null
+++ b/res/drawable/numpad_eight.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_eight_default.png b/res/drawable/numpad_eight_default.png
new file mode 100644
index 000000000..a3c0d8033
Binary files /dev/null and b/res/drawable/numpad_eight_default.png differ
diff --git a/res/drawable/numpad_eight_over.png b/res/drawable/numpad_eight_over.png
new file mode 100644
index 000000000..2ccb7f97c
Binary files /dev/null and b/res/drawable/numpad_eight_over.png differ
diff --git a/res/drawable/numpad_five.xml b/res/drawable/numpad_five.xml
new file mode 100644
index 000000000..3a3c7dcbd
--- /dev/null
+++ b/res/drawable/numpad_five.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_five_default.png b/res/drawable/numpad_five_default.png
new file mode 100644
index 000000000..023eee43b
Binary files /dev/null and b/res/drawable/numpad_five_default.png differ
diff --git a/res/drawable/numpad_five_over.png b/res/drawable/numpad_five_over.png
new file mode 100644
index 000000000..3b4a62e63
Binary files /dev/null and b/res/drawable/numpad_five_over.png differ
diff --git a/res/drawable/numpad_four.xml b/res/drawable/numpad_four.xml
new file mode 100644
index 000000000..7fcef5d78
--- /dev/null
+++ b/res/drawable/numpad_four.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_four_default.png b/res/drawable/numpad_four_default.png
new file mode 100644
index 000000000..fa788a745
Binary files /dev/null and b/res/drawable/numpad_four_default.png differ
diff --git a/res/drawable/numpad_four_over.png b/res/drawable/numpad_four_over.png
new file mode 100644
index 000000000..2bffe94d5
Binary files /dev/null and b/res/drawable/numpad_four_over.png differ
diff --git a/res/drawable/numpad_nine.xml b/res/drawable/numpad_nine.xml
new file mode 100644
index 000000000..51a5637bc
--- /dev/null
+++ b/res/drawable/numpad_nine.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_nine_default.png b/res/drawable/numpad_nine_default.png
new file mode 100644
index 000000000..594a49d5f
Binary files /dev/null and b/res/drawable/numpad_nine_default.png differ
diff --git a/res/drawable/numpad_nine_over.png b/res/drawable/numpad_nine_over.png
new file mode 100644
index 000000000..c457e8400
Binary files /dev/null and b/res/drawable/numpad_nine_over.png differ
diff --git a/res/drawable/numpad_one.xml b/res/drawable/numpad_one.xml
new file mode 100644
index 000000000..0e84886ba
--- /dev/null
+++ b/res/drawable/numpad_one.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_one_default.png b/res/drawable/numpad_one_default.png
new file mode 100644
index 000000000..07f8d0ecf
Binary files /dev/null and b/res/drawable/numpad_one_default.png differ
diff --git a/res/drawable/numpad_one_over.png b/res/drawable/numpad_one_over.png
new file mode 100644
index 000000000..abe10c6e7
Binary files /dev/null and b/res/drawable/numpad_one_over.png differ
diff --git a/res/drawable/numpad_seven.xml b/res/drawable/numpad_seven.xml
new file mode 100644
index 000000000..ce132ee85
--- /dev/null
+++ b/res/drawable/numpad_seven.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_seven_default.png b/res/drawable/numpad_seven_default.png
new file mode 100644
index 000000000..85ea3ddcf
Binary files /dev/null and b/res/drawable/numpad_seven_default.png differ
diff --git a/res/drawable/numpad_seven_over.png b/res/drawable/numpad_seven_over.png
new file mode 100644
index 000000000..9ec319835
Binary files /dev/null and b/res/drawable/numpad_seven_over.png differ
diff --git a/res/drawable/numpad_sharp.xml b/res/drawable/numpad_sharp.xml
new file mode 100644
index 000000000..00f95053c
--- /dev/null
+++ b/res/drawable/numpad_sharp.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_sharp_default.png b/res/drawable/numpad_sharp_default.png
new file mode 100644
index 000000000..c551d9121
Binary files /dev/null and b/res/drawable/numpad_sharp_default.png differ
diff --git a/res/drawable/numpad_sharp_over.png b/res/drawable/numpad_sharp_over.png
new file mode 100644
index 000000000..dffb1b062
Binary files /dev/null and b/res/drawable/numpad_sharp_over.png differ
diff --git a/res/drawable/numpad_six.xml b/res/drawable/numpad_six.xml
new file mode 100644
index 000000000..772a76289
--- /dev/null
+++ b/res/drawable/numpad_six.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_six_default.png b/res/drawable/numpad_six_default.png
new file mode 100644
index 000000000..5404d14ec
Binary files /dev/null and b/res/drawable/numpad_six_default.png differ
diff --git a/res/drawable/numpad_six_over.png b/res/drawable/numpad_six_over.png
new file mode 100644
index 000000000..aee8556d7
Binary files /dev/null and b/res/drawable/numpad_six_over.png differ
diff --git a/res/drawable/numpad_star.xml b/res/drawable/numpad_star.xml
new file mode 100644
index 000000000..ba25790e4
--- /dev/null
+++ b/res/drawable/numpad_star.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_star_default.png b/res/drawable/numpad_star_default.png
new file mode 100644
index 000000000..41c13aa40
Binary files /dev/null and b/res/drawable/numpad_star_default.png differ
diff --git a/res/drawable/numpad_star_over.png b/res/drawable/numpad_star_over.png
new file mode 100644
index 000000000..ac9639ff7
Binary files /dev/null and b/res/drawable/numpad_star_over.png differ
diff --git a/res/drawable/numpad_three.xml b/res/drawable/numpad_three.xml
new file mode 100644
index 000000000..64d9d9ab5
--- /dev/null
+++ b/res/drawable/numpad_three.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_three_default.png b/res/drawable/numpad_three_default.png
new file mode 100644
index 000000000..5a489c493
Binary files /dev/null and b/res/drawable/numpad_three_default.png differ
diff --git a/res/drawable/numpad_three_over.png b/res/drawable/numpad_three_over.png
new file mode 100644
index 000000000..8fb1e1dc8
Binary files /dev/null and b/res/drawable/numpad_three_over.png differ
diff --git a/res/drawable/numpad_two.xml b/res/drawable/numpad_two.xml
new file mode 100644
index 000000000..e65e2a7ed
--- /dev/null
+++ b/res/drawable/numpad_two.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_two_default.png b/res/drawable/numpad_two_default.png
new file mode 100644
index 000000000..0de47b0bb
Binary files /dev/null and b/res/drawable/numpad_two_default.png differ
diff --git a/res/drawable/numpad_two_over.png b/res/drawable/numpad_two_over.png
new file mode 100644
index 000000000..da5f95e90
Binary files /dev/null and b/res/drawable/numpad_two_over.png differ
diff --git a/res/drawable/numpad_zero.xml b/res/drawable/numpad_zero.xml
new file mode 100644
index 000000000..9caee9d41
--- /dev/null
+++ b/res/drawable/numpad_zero.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/numpad_zero_default.png b/res/drawable/numpad_zero_default.png
new file mode 100644
index 000000000..465a3c9f6
Binary files /dev/null and b/res/drawable/numpad_zero_default.png differ
diff --git a/res/drawable/numpad_zero_over.png b/res/drawable/numpad_zero_over.png
new file mode 100644
index 000000000..86c14f38c
Binary files /dev/null and b/res/drawable/numpad_zero_over.png differ
diff --git a/res/drawable/ok.xml b/res/drawable/ok.xml
new file mode 100644
index 000000000..b50da4366
--- /dev/null
+++ b/res/drawable/ok.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/ok_default.png b/res/drawable/ok_default.png
new file mode 100644
index 000000000..7fb188033
Binary files /dev/null and b/res/drawable/ok_default.png differ
diff --git a/res/drawable/ok_over.png b/res/drawable/ok_over.png
new file mode 100644
index 000000000..51411d7db
Binary files /dev/null and b/res/drawable/ok_over.png differ
diff --git a/res/drawable/options_default.png b/res/drawable/options_default.png
new file mode 100644
index 000000000..2a2c832e6
Binary files /dev/null and b/res/drawable/options_default.png differ
diff --git a/res/drawable/options_disabled.png b/res/drawable/options_disabled.png
new file mode 100644
index 000000000..3f5a32482
Binary files /dev/null and b/res/drawable/options_disabled.png differ
diff --git a/res/drawable/options_over.png b/res/drawable/options_over.png
new file mode 100644
index 000000000..4c33e642b
Binary files /dev/null and b/res/drawable/options_over.png differ
diff --git a/res/drawable/out_call.png b/res/drawable/out_call.png
deleted file mode 100644
index 80640c31a..000000000
Binary files a/res/drawable/out_call.png and /dev/null differ
diff --git a/res/drawable/out_call_mini.png b/res/drawable/out_call_mini.png
deleted file mode 100644
index a3abd2de9..000000000
Binary files a/res/drawable/out_call_mini.png and /dev/null differ
diff --git a/res/drawable/pause_default b/res/drawable/pause_default
new file mode 100644
index 000000000..0ca4db8c1
Binary files /dev/null and b/res/drawable/pause_default differ
diff --git a/res/drawable/pause_off.xml b/res/drawable/pause_off.xml
new file mode 100644
index 000000000..3c3479543
--- /dev/null
+++ b/res/drawable/pause_off.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/pause_off_default.png b/res/drawable/pause_off_default.png
new file mode 100644
index 000000000..c6bf04de7
Binary files /dev/null and b/res/drawable/pause_off_default.png differ
diff --git a/res/drawable/pause_off_over.png b/res/drawable/pause_off_over.png
new file mode 100644
index 000000000..7289286c2
Binary files /dev/null and b/res/drawable/pause_off_over.png differ
diff --git a/res/drawable/pause_on.xml b/res/drawable/pause_on.xml
new file mode 100644
index 000000000..b6a96d195
--- /dev/null
+++ b/res/drawable/pause_on.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/drawable/pause_on_default.png b/res/drawable/pause_on_default.png
new file mode 100644
index 000000000..f6c266768
Binary files /dev/null and b/res/drawable/pause_on_default.png differ
diff --git a/res/drawable/pause_on_over.png b/res/drawable/pause_on_over.png
new file mode 100644
index 000000000..8268d1f8a
Binary files /dev/null and b/res/drawable/pause_on_over.png differ
diff --git a/res/drawable/pause_over b/res/drawable/pause_over
new file mode 100644
index 000000000..a2a15e52b
Binary files /dev/null and b/res/drawable/pause_over differ
diff --git a/res/drawable/picker_transfer.png b/res/drawable/picker_transfer.png
deleted file mode 100644
index 0251581f3..000000000
Binary files a/res/drawable/picker_transfer.png and /dev/null differ
diff --git a/res/drawable/play_default b/res/drawable/play_default
new file mode 100644
index 000000000..cf455e337
Binary files /dev/null and b/res/drawable/play_default differ
diff --git a/res/drawable/play_over b/res/drawable/play_over
new file mode 100644
index 000000000..42d81a845
Binary files /dev/null and b/res/drawable/play_over differ
diff --git a/res/drawable/plus.xml b/res/drawable/plus.xml
new file mode 100644
index 000000000..077a07bc2
--- /dev/null
+++ b/res/drawable/plus.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/res/drawable/resume_blue.png b/res/drawable/resume_blue.png
deleted file mode 100644
index 8274e4a8d..000000000
Binary files a/res/drawable/resume_blue.png and /dev/null differ
diff --git a/res/drawable/security_ko.png b/res/drawable/security_ko.png
new file mode 100644
index 000000000..bf75d1b27
Binary files /dev/null and b/res/drawable/security_ko.png differ
diff --git a/res/drawable/security_ok.png b/res/drawable/security_ok.png
new file mode 100644
index 000000000..0a48c7d14
Binary files /dev/null and b/res/drawable/security_ok.png differ
diff --git a/res/drawable/security_pending.png b/res/drawable/security_pending.png
new file mode 100644
index 000000000..1f68accf2
Binary files /dev/null and b/res/drawable/security_pending.png differ
diff --git a/res/drawable/sel_call.png b/res/drawable/sel_call.png
new file mode 100644
index 000000000..f4fd83b8f
Binary files /dev/null and b/res/drawable/sel_call.png differ
diff --git a/res/drawable/sel_call_first.png b/res/drawable/sel_call_first.png
new file mode 100644
index 000000000..17b55ffef
Binary files /dev/null and b/res/drawable/sel_call_first.png differ
diff --git a/res/drawable/settings.xml b/res/drawable/settings.xml
new file mode 100644
index 000000000..365633495
--- /dev/null
+++ b/res/drawable/settings.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/settings_default.png b/res/drawable/settings_default.png
new file mode 100644
index 000000000..ecf4ab11b
Binary files /dev/null and b/res/drawable/settings_default.png differ
diff --git a/res/drawable/settings_over.png b/res/drawable/settings_over.png
new file mode 100644
index 000000000..37339b4af
Binary files /dev/null and b/res/drawable/settings_over.png differ
diff --git a/res/drawable/settings_selected.png b/res/drawable/settings_selected.png
new file mode 100644
index 000000000..1befba3bf
Binary files /dev/null and b/res/drawable/settings_selected.png differ
diff --git a/res/drawable/setup_back.xml b/res/drawable/setup_back.xml
new file mode 100644
index 000000000..c5fb0fbe1
--- /dev/null
+++ b/res/drawable/setup_back.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/setup_back_default.png b/res/drawable/setup_back_default.png
new file mode 100644
index 000000000..d71825b83
Binary files /dev/null and b/res/drawable/setup_back_default.png differ
diff --git a/res/drawable/setup_back_disabled.png b/res/drawable/setup_back_disabled.png
new file mode 100644
index 000000000..805084589
Binary files /dev/null and b/res/drawable/setup_back_disabled.png differ
diff --git a/res/drawable/setup_back_over.png b/res/drawable/setup_back_over.png
new file mode 100644
index 000000000..ed550a18d
Binary files /dev/null and b/res/drawable/setup_back_over.png differ
diff --git a/res/drawable/setup_cancel.xml b/res/drawable/setup_cancel.xml
new file mode 100644
index 000000000..e4f34cd9f
--- /dev/null
+++ b/res/drawable/setup_cancel.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/setup_cancel_default.png b/res/drawable/setup_cancel_default.png
new file mode 100644
index 000000000..43635712e
Binary files /dev/null and b/res/drawable/setup_cancel_default.png differ
diff --git a/res/drawable/setup_cancel_disabled.png b/res/drawable/setup_cancel_disabled.png
new file mode 100644
index 000000000..30b9978fa
Binary files /dev/null and b/res/drawable/setup_cancel_disabled.png differ
diff --git a/res/drawable/setup_cancel_over.png b/res/drawable/setup_cancel_over.png
new file mode 100644
index 000000000..470da607e
Binary files /dev/null and b/res/drawable/setup_cancel_over.png differ
diff --git a/res/drawable/setup_label.png b/res/drawable/setup_label.png
new file mode 100644
index 000000000..7b8cb1ed5
Binary files /dev/null and b/res/drawable/setup_label.png differ
diff --git a/res/drawable/setup_letsgo_default.png b/res/drawable/setup_letsgo_default.png
new file mode 100644
index 000000000..8719b6507
Binary files /dev/null and b/res/drawable/setup_letsgo_default.png differ
diff --git a/res/drawable/setup_letsgo_disabled.png b/res/drawable/setup_letsgo_disabled.png
new file mode 100644
index 000000000..1c66451b3
Binary files /dev/null and b/res/drawable/setup_letsgo_disabled.png differ
diff --git a/res/drawable/setup_letsgo_over.png b/res/drawable/setup_letsgo_over.png
new file mode 100644
index 000000000..160a9e1c2
Binary files /dev/null and b/res/drawable/setup_letsgo_over.png differ
diff --git a/res/drawable/setup_next.xml b/res/drawable/setup_next.xml
new file mode 100644
index 000000000..505a42a16
--- /dev/null
+++ b/res/drawable/setup_next.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/setup_title_assistant.png b/res/drawable/setup_title_assistant.png
new file mode 100644
index 000000000..275ed24b1
Binary files /dev/null and b/res/drawable/setup_title_assistant.png differ
diff --git a/res/drawable/setup_welcome_logo.png b/res/drawable/setup_welcome_logo.png
new file mode 100644
index 000000000..d257f3158
Binary files /dev/null and b/res/drawable/setup_welcome_logo.png differ
diff --git a/res/drawable/slider_left.9.png b/res/drawable/slider_left.9.png
new file mode 100644
index 000000000..4cb9421d9
Binary files /dev/null and b/res/drawable/slider_left.9.png differ
diff --git a/res/drawable/slider_right.9.png b/res/drawable/slider_right.9.png
new file mode 100644
index 000000000..d0a8f1670
Binary files /dev/null and b/res/drawable/slider_right.9.png differ
diff --git a/res/drawable/speaker_32_off.png b/res/drawable/speaker_32_off.png
deleted file mode 100644
index e93ae232f..000000000
Binary files a/res/drawable/speaker_32_off.png and /dev/null differ
diff --git a/res/drawable/speaker_32_on.png b/res/drawable/speaker_32_on.png
deleted file mode 100644
index de8d4460e..000000000
Binary files a/res/drawable/speaker_32_on.png and /dev/null differ
diff --git a/res/drawable/speaker_off.xml b/res/drawable/speaker_off.xml
new file mode 100644
index 000000000..125cebfe2
--- /dev/null
+++ b/res/drawable/speaker_off.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/speaker_off_default.png b/res/drawable/speaker_off_default.png
new file mode 100644
index 000000000..5094dd200
Binary files /dev/null and b/res/drawable/speaker_off_default.png differ
diff --git a/res/drawable/speaker_off_disabled.png b/res/drawable/speaker_off_disabled.png
new file mode 100644
index 000000000..cb5a1dcf7
Binary files /dev/null and b/res/drawable/speaker_off_disabled.png differ
diff --git a/res/drawable/speaker_off_over.png b/res/drawable/speaker_off_over.png
new file mode 100644
index 000000000..bd1779182
Binary files /dev/null and b/res/drawable/speaker_off_over.png differ
diff --git a/res/drawable/speaker_on.xml b/res/drawable/speaker_on.xml
new file mode 100644
index 000000000..b1e7ce119
--- /dev/null
+++ b/res/drawable/speaker_on.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/speaker_on_default.png b/res/drawable/speaker_on_default.png
new file mode 100644
index 000000000..2f4f58440
Binary files /dev/null and b/res/drawable/speaker_on_default.png differ
diff --git a/res/drawable/speaker_on_disabled.png b/res/drawable/speaker_on_disabled.png
new file mode 100644
index 000000000..a07dc1f5c
Binary files /dev/null and b/res/drawable/speaker_on_disabled.png differ
diff --git a/res/drawable/speaker_on_over.png b/res/drawable/speaker_on_over.png
new file mode 100644
index 000000000..e9b54f839
Binary files /dev/null and b/res/drawable/speaker_on_over.png differ
diff --git a/res/drawable/startcall_green.png b/res/drawable/startcall_green.png
deleted file mode 100644
index 940802a0c..000000000
Binary files a/res/drawable/startcall_green.png and /dev/null differ
diff --git a/res/drawable/startvideo_green.png b/res/drawable/startvideo_green.png
deleted file mode 100644
index 1cc2e3e4b..000000000
Binary files a/res/drawable/startvideo_green.png and /dev/null differ
diff --git a/res/drawable/stat_sys_signal_0.png b/res/drawable/stat_sys_signal_0.png
deleted file mode 100644
index 0b7a04f44..000000000
Binary files a/res/drawable/stat_sys_signal_0.png and /dev/null differ
diff --git a/res/drawable/stat_sys_signal_1.png b/res/drawable/stat_sys_signal_1.png
deleted file mode 100644
index 5376e9258..000000000
Binary files a/res/drawable/stat_sys_signal_1.png and /dev/null differ
diff --git a/res/drawable/stat_sys_signal_2.png b/res/drawable/stat_sys_signal_2.png
deleted file mode 100644
index fd543636c..000000000
Binary files a/res/drawable/stat_sys_signal_2.png and /dev/null differ
diff --git a/res/drawable/stat_sys_signal_3.png b/res/drawable/stat_sys_signal_3.png
deleted file mode 100644
index 6c4873af3..000000000
Binary files a/res/drawable/stat_sys_signal_3.png and /dev/null differ
diff --git a/res/drawable/stat_sys_signal_4.png b/res/drawable/stat_sys_signal_4.png
deleted file mode 100644
index a3320cbb4..000000000
Binary files a/res/drawable/stat_sys_signal_4.png and /dev/null differ
diff --git a/res/drawable/stopcall_red.png b/res/drawable/stopcall_red.png
deleted file mode 100644
index 1004b8a01..000000000
Binary files a/res/drawable/stopcall_red.png and /dev/null differ
diff --git a/res/drawable/switch_camera.xml b/res/drawable/switch_camera.xml
new file mode 100644
index 000000000..f0e714934
--- /dev/null
+++ b/res/drawable/switch_camera.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/res/drawable/switch_camera_default.png b/res/drawable/switch_camera_default.png
new file mode 100644
index 000000000..2145e1db3
Binary files /dev/null and b/res/drawable/switch_camera_default.png differ
diff --git a/res/drawable/switch_camera_over.png b/res/drawable/switch_camera_over.png
new file mode 100644
index 000000000..649861e9f
Binary files /dev/null and b/res/drawable/switch_camera_over.png differ
diff --git a/res/drawable/unknown_person.png b/res/drawable/unknown_person.png
deleted file mode 100755
index 297b14b14..000000000
Binary files a/res/drawable/unknown_person.png and /dev/null differ
diff --git a/res/drawable/unknown_small.png b/res/drawable/unknown_small.png
new file mode 100644
index 000000000..143da1512
Binary files /dev/null and b/res/drawable/unknown_small.png differ
diff --git a/res/drawable/video_active.png b/res/drawable/video_active.png
deleted file mode 100644
index c6bb5ddce..000000000
Binary files a/res/drawable/video_active.png and /dev/null differ
diff --git a/res/drawable/video_muted.png b/res/drawable/video_muted.png
deleted file mode 100644
index c9f83aee1..000000000
Binary files a/res/drawable/video_muted.png and /dev/null differ
diff --git a/res/drawable/video_off.xml b/res/drawable/video_off.xml
new file mode 100644
index 000000000..ded805ba2
--- /dev/null
+++ b/res/drawable/video_off.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/video_off_default.png b/res/drawable/video_off_default.png
new file mode 100644
index 000000000..8e80dd7a6
Binary files /dev/null and b/res/drawable/video_off_default.png differ
diff --git a/res/drawable/video_off_disabled.png b/res/drawable/video_off_disabled.png
new file mode 100644
index 000000000..d9806305d
Binary files /dev/null and b/res/drawable/video_off_disabled.png differ
diff --git a/res/drawable/video_off_over.png b/res/drawable/video_off_over.png
new file mode 100644
index 000000000..26a00c41e
Binary files /dev/null and b/res/drawable/video_off_over.png differ
diff --git a/res/drawable/video_on.xml b/res/drawable/video_on.xml
new file mode 100644
index 000000000..851cef5ef
--- /dev/null
+++ b/res/drawable/video_on.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/res/drawable/video_on_default.png b/res/drawable/video_on_default.png
new file mode 100644
index 000000000..dde8964d9
Binary files /dev/null and b/res/drawable/video_on_default.png differ
diff --git a/res/drawable/video_on_disabled.png b/res/drawable/video_on_disabled.png
new file mode 100644
index 000000000..02a1cc236
Binary files /dev/null and b/res/drawable/video_on_disabled.png differ
diff --git a/res/drawable/video_on_over.png b/res/drawable/video_on_over.png
new file mode 100644
index 000000000..20fa87e9b
Binary files /dev/null and b/res/drawable/video_on_over.png differ
diff --git a/res/drawable/notok.png b/res/drawable/wizard_notok.png
similarity index 100%
rename from res/drawable/notok.png
rename to res/drawable/wizard_notok.png
diff --git a/res/drawable/ok.png b/res/drawable/wizard_ok.png
similarity index 100%
rename from res/drawable/ok.png
rename to res/drawable/wizard_ok.png
diff --git a/res/layout-land/dialer.xml b/res/layout-land/dialer.xml
deleted file mode 100644
index 3a1326c69..000000000
--- a/res/layout-land/dialer.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout-land/videocall.xml b/res/layout-land/videocall.xml
deleted file mode 100755
index 2d39b8f84..000000000
--- a/res/layout-land/videocall.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout-xlarge/dialer.xml b/res/layout-xlarge/dialer.xml
deleted file mode 100644
index 9d0dbba6a..000000000
--- a/res/layout-xlarge/dialer.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout-xlarge/incall_layout.xml b/res/layout-xlarge/incall_layout.xml
deleted file mode 100644
index c5f84add3..000000000
--- a/res/layout-xlarge/incall_layout.xml
+++ /dev/null
@@ -1,149 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout-xlarge/videocall.xml b/res/layout-xlarge/videocall.xml
deleted file mode 100755
index 310aa47e8..000000000
--- a/res/layout-xlarge/videocall.xml
+++ /dev/null
@@ -1,128 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout/about.xml b/res/layout/about.xml
deleted file mode 100644
index ab2a6883f..000000000
--- a/res/layout/about.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
diff --git a/res/layout/accounts.xml b/res/layout/accounts.xml
deleted file mode 100644
index c0065ef70..000000000
--- a/res/layout/accounts.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/res/layout/active_call.xml b/res/layout/active_call.xml
new file mode 100644
index 000000000..55b853b7b
--- /dev/null
+++ b/res/layout/active_call.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/audio.xml b/res/layout/audio.xml
new file mode 100644
index 000000000..97e8a0aad
--- /dev/null
+++ b/res/layout/audio.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/chat.xml b/res/layout/chat.xml
new file mode 100644
index 000000000..84104801c
--- /dev/null
+++ b/res/layout/chat.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/chatlist.xml b/res/layout/chatlist.xml
new file mode 100644
index 000000000..9b894bf40
--- /dev/null
+++ b/res/layout/chatlist.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/chatlist_cell.xml b/res/layout/chatlist_cell.xml
new file mode 100644
index 000000000..2d56249ed
--- /dev/null
+++ b/res/layout/chatlist_cell.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/conf_callee.xml b/res/layout/conf_callee.xml
deleted file mode 100644
index e3792b58d..000000000
--- a/res/layout/conf_callee.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/conf_callee_older_devices.xml b/res/layout/conf_callee_older_devices.xml
deleted file mode 100644
index e3d52dfee..000000000
--- a/res/layout/conf_callee_older_devices.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/conf_choices_dialog.xml b/res/layout/conf_choices_dialog.xml
deleted file mode 100644
index f5e420f0e..000000000
--- a/res/layout/conf_choices_dialog.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout/conf_details_participant_choices_dialog.xml b/res/layout/conf_details_participant_choices_dialog.xml
deleted file mode 100644
index f7a79b68e..000000000
--- a/res/layout/conf_details_participant_choices_dialog.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout/conference_details_layout.xml b/res/layout/conference_details_layout.xml
deleted file mode 100644
index 231719e79..000000000
--- a/res/layout/conference_details_layout.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/contact.xml b/res/layout/contact.xml
new file mode 100644
index 000000000..fcca3d240
--- /dev/null
+++ b/res/layout/contact.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/contact_cell.xml b/res/layout/contact_cell.xml
new file mode 100644
index 000000000..c9dfa97ab
--- /dev/null
+++ b/res/layout/contact_cell.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/contact_control_row.xml b/res/layout/contact_control_row.xml
new file mode 100644
index 000000000..3a17fba19
--- /dev/null
+++ b/res/layout/contact_control_row.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/contact_picker.xml b/res/layout/contact_picker.xml
deleted file mode 100644
index 9ad7a12e1..000000000
--- a/res/layout/contact_picker.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/res/layout/contacts_list.xml b/res/layout/contacts_list.xml
new file mode 100644
index 000000000..38e2c1b3e
--- /dev/null
+++ b/res/layout/contacts_list.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/dialer.xml b/res/layout/dialer.xml
index 5b80a9f8c..f326ee14c 100644
--- a/res/layout/dialer.xml
+++ b/res/layout/dialer.xml
@@ -1,125 +1,59 @@
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/first_login_view.xml b/res/layout/first_login_view.xml
deleted file mode 100644
index 225263010..000000000
--- a/res/layout/first_login_view.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout/hello_world.xml b/res/layout/hello_world.xml
deleted file mode 100644
index 25d396656..000000000
--- a/res/layout/hello_world.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/history.xml b/res/layout/history.xml
new file mode 100644
index 000000000..7f186db3b
--- /dev/null
+++ b/res/layout/history.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/history_cell.xml b/res/layout/history_cell.xml
index 108d35b06..a1a3f7c74 100644
--- a/res/layout/history_cell.xml
+++ b/res/layout/history_cell.xml
@@ -1,43 +1,48 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/history_detail.xml b/res/layout/history_detail.xml
new file mode 100644
index 000000000..31fa60b66
--- /dev/null
+++ b/res/layout/history_detail.xml
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/incall.xml b/res/layout/incall.xml
new file mode 100644
index 000000000..0223622f0
--- /dev/null
+++ b/res/layout/incall.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/incall_layout.xml b/res/layout/incall_layout.xml
deleted file mode 100644
index a5bfa8ba9..000000000
--- a/res/layout/incall_layout.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/incoming.xml b/res/layout/incoming.xml
index de9f8f09f..871f134ad 100644
--- a/res/layout/incoming.xml
+++ b/res/layout/incoming.xml
@@ -1,55 +1,59 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_marginBottom="80dip" />
diff --git a/res/layout/incoming_call.xml b/res/layout/incoming_call.xml
deleted file mode 100644
index adc5a351c..000000000
--- a/res/layout/incoming_call.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/main.xml b/res/layout/main.xml
index be34db025..9e42fa0fe 100644
--- a/res/layout/main.xml
+++ b/res/layout/main.xml
@@ -1,19 +1,109 @@
-
-
-
-
-
-
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/res/layout/numpad.xml b/res/layout/numpad.xml
index 9e65e4805..8ed3fb8ae 100644
--- a/res/layout/numpad.xml
+++ b/res/layout/numpad.xml
@@ -4,28 +4,29 @@
android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1">
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/ring.xml b/res/layout/ring.xml
deleted file mode 100644
index 21e0e01bc..000000000
--- a/res/layout/ring.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
diff --git a/res/layout/settings.xml b/res/layout/settings.xml
new file mode 100644
index 000000000..2518bf3e2
--- /dev/null
+++ b/res/layout/settings.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/setup.xml b/res/layout/setup.xml
new file mode 100644
index 000000000..6db471a82
--- /dev/null
+++ b/res/layout/setup.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/setup_generic_login.xml b/res/layout/setup_generic_login.xml
new file mode 100644
index 000000000..4fc7e8ff1
--- /dev/null
+++ b/res/layout/setup_generic_login.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/setup_linphone_login.xml b/res/layout/setup_linphone_login.xml
new file mode 100644
index 000000000..6c5ba2212
--- /dev/null
+++ b/res/layout/setup_linphone_login.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/setup_menu.xml b/res/layout/setup_menu.xml
new file mode 100644
index 000000000..0aadb9308
--- /dev/null
+++ b/res/layout/setup_menu.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/setup_welcome.xml b/res/layout/setup_welcome.xml
new file mode 100644
index 000000000..717678cec
--- /dev/null
+++ b/res/layout/setup_welcome.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/setup_wizard.xml b/res/layout/setup_wizard.xml
new file mode 100644
index 000000000..f0fd0fba1
--- /dev/null
+++ b/res/layout/setup_wizard.xml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/setup_wizard_confirm.xml b/res/layout/setup_wizard_confirm.xml
new file mode 100644
index 000000000..757cf1d9a
--- /dev/null
+++ b/res/layout/setup_wizard_confirm.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/simplified_dialer.xml b/res/layout/simplified_dialer.xml
deleted file mode 100644
index 7159abdb1..000000000
--- a/res/layout/simplified_dialer.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/layout/status.xml b/res/layout/status.xml
new file mode 100644
index 000000000..0369d38de
--- /dev/null
+++ b/res/layout/status.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/uri_picker.xml b/res/layout/uri_picker.xml
deleted file mode 100644
index be34db025..000000000
--- a/res/layout/uri_picker.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout/video.xml b/res/layout/video.xml
new file mode 100644
index 000000000..77287d5a8
--- /dev/null
+++ b/res/layout/video.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/videocall.xml b/res/layout/videocall.xml
deleted file mode 100755
index 268cf08d6..000000000
--- a/res/layout/videocall.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout/wizard.xml b/res/layout/wizard.xml
deleted file mode 100644
index 25dd1f314..000000000
--- a/res/layout/wizard.xml
+++ /dev/null
@@ -1,115 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/layout/wizard_confirm.xml b/res/layout/wizard_confirm.xml
deleted file mode 100644
index c3020b989..000000000
--- a/res/layout/wizard_confirm.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/menu/history_activity_menu.xml b/res/menu/history_activity_menu.xml
deleted file mode 100644
index f1d6161a1..000000000
--- a/res/menu/history_activity_menu.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
diff --git a/res/menu/linphone_activity_menu.xml b/res/menu/linphone_activity_menu.xml
deleted file mode 100644
index 415be3aa9..000000000
--- a/res/menu/linphone_activity_menu.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
diff --git a/res/menu/videocall_activity_menu.xml b/res/menu/videocall_activity_menu.xml
deleted file mode 100644
index 88dca9776..000000000
--- a/res/menu/videocall_activity_menu.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
diff --git a/res/raw-xlarge/linphonerc b/res/raw-xlarge/linphonerc
deleted file mode 100644
index e6b2f09da..000000000
--- a/res/raw-xlarge/linphonerc
+++ /dev/null
@@ -1,52 +0,0 @@
-[net]
-download_bw=512
-upload_bw=512
-firewall_policy=0
-mtu=1300
-#adaptive_rate_control=1
-
-[sip]
-sip_port=5060
-sip_random_port=1
-guess_hostname=1
-contact=sip:unknown@unknown-host
-inc_timeout=15
-use_info=0
-use_ipv6=0
-register_only_when_network_is_up=1
-default_proxy=0
-auto_net_state_mon=0
-keepalive_period=30000
-auto_answer_replacing_calls=1
-media_encryption=zrtp
-media_encryption_mandatory=0
-
-[rtp]
-audio_rtp_port=7076
-video_rtp_port=9078
-audio_jitt_comp=60
-video_jitt_comp=60
-nortp_timeout=30
-
-[sound]
-playback_dev_id=ANDROID SND: Android Sound card
-ringer_dev_id=ANDROID SND: Android Sound card
-capture_dev_id=ANDROID SND: Android Sound card
-remote_ring=/data/data/org.linphone/files/ringback.wav
-local_ring=/data/data/org.linphone/files/oldphone_mono.wav
-ec_tail_len=120
-ec_framesize=128
-
-el_type=mic
-el_thres=0.03
-el_force=100000
-el_sustain=600
-el_transmit_thres=1.7
-ng_floorgain=0.01
-
-
-[video]
-size=vga
-
-[misc]
-max_calls=10
diff --git a/res/values/callee_style.xml b/res/values/callee_style.xml
deleted file mode 100644
index 7107e9915..000000000
--- a/res/values/callee_style.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/values/color.xml b/res/values/color.xml
new file mode 100644
index 000000000..d89cec8e4
--- /dev/null
+++ b/res/values/color.xml
@@ -0,0 +1,7 @@
+
+
+ #ffe4edf2
+ #ffd8d8d8
+ #ffb1bdc3
+ #ffcf4c29
+
\ No newline at end of file
diff --git a/res/values/conf_style.xml b/res/values/conf_style.xml
deleted file mode 100644
index 58d1109d8..000000000
--- a/res/values/conf_style.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/values/custom.xml b/res/values/custom.xml
index 8f4ef1b67..a5c050b2e 100644
--- a/res/values/custom.xml
+++ b/res/values/custom.xml
@@ -1,8 +1,11 @@
-
- Linphone
+ HH:mm:ss d MMM
+ few seconds ago
+ HH:mm:ss
+
+ Linphone 2
Linphone
Starting up
Registered to %s
diff --git a/res/values/digit_style.xml b/res/values/digit_style.xml
index 60a163c72..7b668bd94 100644
--- a/res/values/digit_style.xml
+++ b/res/values/digit_style.xml
@@ -3,15 +3,11 @@
-
-
diff --git a/res/values/non_localizable_custom.xml b/res/values/non_localizable_custom.xml
index d42ef16b1..ccdf87f45 100644
--- a/res/values/non_localizable_custom.xml
+++ b/res/values/non_localizable_custom.xml
@@ -2,26 +2,22 @@
- test.linphone.org
+ sip.linphone.org
+ https://www.linphone.org/wizard.php
- true
- false
+
false
false
false
- false
false
- true
- true
+ false
+ true
true
- false
+ true
true
true
-
true
- #191970
-
false
linphone-android@belledonne-communications.com
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3ee1e4190..0661b1fab 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -241,13 +241,6 @@
Use wifi only
-Username
-Password
-Confirmation
-Email
-Account Wizard
-Create Account
-Cancel
An error occurred, try again later.
Server unreachable, verify your internet connection.
This username is already in use.
@@ -255,12 +248,68 @@
Your email is not valid.
Your password is not valid (6 characters min).
Passwords entered are different.
-You need to activate your account with the link that was send to your email.
-Confirmation
-Check
SIP proxy hostname or ip address (optional)
Route all calls through SIP proxy
Example: john if your account is john@sip.linphone.org
sip.linphone.org if your account is john@sip.linphone.org
+
+Chat
+Add to contacts
+CONNECTED
+NOT CONNECTED
+
+
+Add to contacts button
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Account Setup Assistant
+This assistant will help you to use a SIP account for your calls.
+Create an account on linphone.org
+I already have a linphone.org account
+I already have a SIP account
+Enter your linphone.org username and password
+Apply
+username
+password
+domain
+confirm password
+email
+Create Account
+An email has been sent to the address you gave. In order to activate your account, you need to click on the link inside it. Once it is done, come back here and click on the button above.
+Check
+Your account has not been validated yet.
+Your account has been validated.
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 3e7a9948e..6ec2d3d6f 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -1,6 +1,7 @@
+
-
-
+
mSpecificCalls = Collections.emptyList();
- private Handler mHandler = new Handler();
-
- private Checkable mMuteMicButton;
- private Checkable mSpeakerButton;
-
- protected abstract boolean isActive();
- protected abstract void setActive(boolean active);
-
- protected abstract List updateSpecificCallsList();
-
- private Set mChronometers = new HashSet();
-
- private Handler callqualityHandler;
- private List viewsToUpdateCallQuality;
- private boolean shouldDisplayWhoIsTalking = false;
- @Override
- /**
- * Called by the child classes AFTER their own onCreate.
- */
- protected void onCreate(Bundle savedInstanceState) {
- if (finishIfAutoRestartAfterACrash(savedInstanceState)) {
- return;
- }
- setListAdapter(mListAdapter = createCalleeListAdapter());
-
- View muteMic = findViewById(R.id.toggleMuteMic);
- muteMic.setOnClickListener(this);
- mMuteMicButton = (Checkable) muteMic;
-
- View speaker = findViewById(R.id.toggleSpeaker);
- speaker.setOnClickListener(this);
- mSpeakerButton = (Checkable) speaker;
- if (LinphoneManager.getInstance().isSpeakerOn()) {
- ((ToggleImageButton) speaker).setChecked(true);
- }
- super.onCreate(savedInstanceState);
- }
-
- protected abstract CalleeListAdapter createCalleeListAdapter();
-
- protected final boolean finishIfAutoRestartAfterACrash(Bundle savedInstanceState) {
- if (!LinphoneManager.isInstanciated() || LinphoneManager.getLc().getCallsNb() == 0) {
- if (!LinphoneManager.isInstanciated()) {
- Log.e("No service running: avoid crash by finishing ", this.getClass().getName());
- }
- super.onCreate(savedInstanceState);
- finish();
- return true;
- }
- return false;
- }
-
- @Override
- protected void onResume() {
- mSpecificCalls = updateSpecificCallsList();
- if (shouldFinishCalleeActivity()) {
- finish();
- } else {
- setActive(true);
- updateUI();
- mSpeakerButton.setChecked(LinphoneManager.getInstance().isSpeakerOn());
- mMuteMicButton.setChecked(LinphoneManager.getLc().isMicMuted());
- LinphoneManager.addListener(this);
- LinphoneManager.startProximitySensorForActivity(this);
- }
- super.onResume();
- }
-
- // Hook
- protected boolean shouldFinishCalleeActivity() {
- return mSpecificCalls.size() == 0;
- }
-
- @Override
- protected void onPause() {
- LinphoneManager.removeListener(this);
- LinphoneManager.stopProximitySensorForActivity(this);
- setActive(false);
- if (isFinishing()) {
- stopChronometers();
- }
- super.onPause();
- }
-
- @Override
- public void onCallStateChanged(LinphoneCall c, State s, String m) {
- mHandler.post(new Runnable() {
- public void run() {
- mSpecificCalls = updateSpecificCallsList();
- if (shouldFinishCalleeActivity()) {
- finish();
- } else {
- updateUI();
- }
- }
- });
- }
-
- protected LinphoneCore lc() {
- return LinphoneManager.getLc();
- }
-
- private void stopChronometers() {
- for (Chronometer chrono : mChronometers) {
- chrono.stop();
- }
- mChronometers.clear();
- }
-
- protected void updateUI() {
- stopChronometers();
- mListAdapter.notifyDataSetChanged();
- }
-
-
- protected void enableView(View root, int id, OnClickListener l, boolean enable) {
- LinphoneUtils.enableView(root, id, l, enable);
- }
-
- protected String getCalleeDisplayOrUserName(LinphoneAddress address) {
- if (!TextUtils.isEmpty(address.getDisplayName())) {
- return address.getDisplayName();
- } else {
- return address.getUserName();
- }
- }
-
- protected void setCalleePicture(ImageView pictureView, LinphoneAddress address) {
- // May be greatly sped up using a drawable cache
- Uri uri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, getContentResolver());
- LinphoneUtils.setImagePictureFromUri(AbstractCalleesActivity.this, pictureView, uri, R.drawable.unknown_person);
- }
-
- protected void setVisibility(View v, int id, boolean visible) {
- LinphoneUtils.setVisibility(v, id, visible);
- }
- protected void setVisibility(View v, boolean visible) {
- LinphoneUtils.setVisibility(v, visible);
- }
-
- protected abstract class CalleeListAdapter extends BaseAdapter {
- protected final List getSpecificCalls() {
- return mSpecificCalls;
- }
- public int getCount() {
- return mSpecificCalls.size();
- }
-
- public LinphoneCall getItem(int position) {
- return mSpecificCalls.get(position);
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- protected final void registerCallDurationTimer(View v, LinphoneCall call) {
- int callDuration = call.getDuration();
- if (callDuration == 0 && call.getState() != State.StreamsRunning) return;
- Chronometer timer = (Chronometer) v.findViewById(R.id.callee_duration);
- if (timer == null) throw new IllegalArgumentException("no callee_duration view found");
- timer.setBase(SystemClock.elapsedRealtime() - 1000 * callDuration);
- timer.start();
- }
-
- protected final void initCallQualityListener() {
- final int timeToRefresh;
- if (shouldDisplayWhoIsTalking)
- timeToRefresh = 100;
- else
- timeToRefresh = 1000;
-
- callqualityHandler = new Handler();
- viewsToUpdateCallQuality = new ArrayList();
- callqualityHandler.postDelayed(new Runnable() {
- public void run() {
- if (viewsToUpdateCallQuality == null) {
- return;
- }
-
- for (View v : viewsToUpdateCallQuality) {
- LinphoneCall call = (LinphoneCall) v.getTag();
- float newQuality = call.getCurrentQuality();
- updateQualityOfSignalIcon(v, newQuality);
-
- // We also use this handler to display the ones who speaks
- ImageView speaking = (ImageView) v.findViewById(R.id.callee_status_speeking);
- if (shouldDisplayWhoIsTalking && call.getPlayVolume() >= -20) {
- speaking.setVisibility(View.VISIBLE);
- } else if (speaking.getVisibility() != View.GONE) {
- speaking.setVisibility(View.GONE);
- }
- }
-
- callqualityHandler.postDelayed(this, timeToRefresh);
- }
- },timeToRefresh);
- }
-
- protected final void registerCallQualityListener(final View v, final LinphoneCall call) {
- if (viewsToUpdateCallQuality == null && callqualityHandler == null) {
- initCallQualityListener();
- }
- v.setTag(call);
- viewsToUpdateCallQuality.add(v);
- }
-
- protected final void registerCallSpeakerListener() {
- shouldDisplayWhoIsTalking = true;
- }
- }
-
- @Override
- public void onClick(View v) {
- int id = v.getId();
- if (id == R.id.toggleMuteMic) {
- lc().muteMic(((Checkable) v).isChecked());
- }
- else if (id == R.id.toggleSpeaker) {
- if (((Checkable) v).isChecked()) {
- LinphoneManager.getInstance().routeAudioToSpeaker();
- } else {
- LinphoneManager.getInstance().routeAudioToReceiver();
- }
- }
- }
-
- @Override
- public void onAudioStateChanged(final AudioState state) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- switch (state) {
- case SPEAKER:
- mSpeakerButton.setChecked(true);
- break;
- case EARPIECE:
- mSpeakerButton.setChecked(false);
- break;
- default:
- throw new RuntimeException("Unknown audio state " + state);
- }
- }
- });
- }
-
- void updateQualityOfSignalIcon(View v, float quality)
- {
- ImageView qos = (ImageView) v.findViewById(R.id.callee_status_qos);
- if (!(qos.getVisibility() == View.VISIBLE)) {
- qos.setVisibility(View.VISIBLE);
- }
- if (quality >= 4) // Good Quality
- {
- qos.setImageDrawable(getResources().getDrawable(R.drawable.stat_sys_signal_4));
- }
- else if (quality >= 3) // Average quality
- {
- qos.setImageDrawable(getResources().getDrawable(R.drawable.stat_sys_signal_3));
- }
- else if (quality >= 2) // Low quality
- {
- qos.setImageDrawable(getResources().getDrawable(R.drawable.stat_sys_signal_2));
- }
- else if (quality >= 1) // Very low quality
- {
- qos.setImageDrawable(getResources().getDrawable(R.drawable.stat_sys_signal_1));
- }
- else // Worst quality
- {
- qos.setImageDrawable(getResources().getDrawable(R.drawable.stat_sys_signal_0));
- }
- }
-}
\ No newline at end of file
diff --git a/src/org/linphone/AbstractContactPickerActivityNew.java b/src/org/linphone/AbstractContactPickerActivityNew.java
deleted file mode 100644
index 87f6dcc5b..000000000
--- a/src/org/linphone/AbstractContactPickerActivityNew.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
-ContactPickerActivity.java
-Copyright (C) 2010 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.List;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.EditText;
-import android.widget.FilterQueryProvider;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.widget.AdapterView.OnItemClickListener;
-
-
-/**
- * Activity for retrieving a phone number / SIP address to call.
- *
- *
- * The cinematic is:
- *
- * - Select contact (either through native or custom way)
- * - Select phone number or SIP address
- *
- Back to dialer
- *
- *
- * @author Guillaume Beraudo
- *
- */
-public abstract class AbstractContactPickerActivityNew extends Activity implements FilterQueryProvider {
-
- private ListView mContactList;
- protected EditText mcontactFilter;
-
- private SimpleCursorAdapter adapter;
- protected boolean useNativePicker;
-
- protected final String col_display_name = "display_name";
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- useNativePicker = getResources().getBoolean(R.bool.use_android_contact_picker);
-
- if (!useNativePicker) {
- setContentView(R.layout.contact_picker);
- createCustomPicker();
- }
-
- onNewIntent(getIntent());
- }
-
-
-
- protected void createCustomPicker() {
- mContactList = (ListView) findViewById(R.id.contactList);
-
- mcontactFilter = (EditText) findViewById(R.id.contactFilter);
- mcontactFilter.addTextChangedListener(new TextWatcher() {
- public void onTextChanged(CharSequence s, int start, int b, int c) {}
- public void beforeTextChanged(CharSequence s, int st, int c, int a) {}
-
- public void afterTextChanged(Editable s) {
- adapter.runQueryOnBackgroundThread(s);
- adapter.getFilter().filter(s.toString());
- }
- });
-
-
- // Populate the contact list
- String[] from = new String[] {col_display_name};
- int[] to = new int[] {android.R.id.text1};
- int layout = android.R.layout.simple_list_item_1;
- adapter = new SimpleCursorAdapter(this, layout, runQuery(null), from, to);
- adapter.setFilterQueryProvider(this);
- mContactList.setAdapter(adapter);
-
- mContactList.setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView> parent, View view, int position, long id) {
- final CharSequence contactName = ((TextView) view.findViewById(android.R.id.text1)).getText();
- choosePhoneNumberAndDial(contactName, String.valueOf(id));
- }
- });
- }
-
-
-
- protected void choosePhoneNumberAndDial(final CharSequence contactName, final String id) {
- List phones = extractPhones(id);
- phones.addAll(extractSipNumbers(id));
-
- switch (phones.size()) {
- case 0:
- String msg = String.format(getString(R.string.no_phone_numbers), contactName);
- Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
- ((ContactPicked) getParent()).goToDialer();
- break;
- case 1:
- returnSelectedValues(phones.get(0), contactName.toString(), getPhotoUri(id));
- break;
- default:
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
-
- final ArrayAdapter pAdapter = new ArrayAdapter(this,
- android.R.layout.simple_dropdown_item_1line, phones);
-
- builder.setTitle(String.format(getString(R.string.title_numbers_dialog),contactName));
- builder.setAdapter(pAdapter, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- returnSelectedValues(pAdapter.getItem(which), contactName.toString(),getPhotoUri(id));
- }
- });
- builder.setCancelable(true);
- builder.setNeutralButton("cancel", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- });
- builder.create().show();
- }
- }
-
- private void returnSelectedValues(String number, String name, Uri photo) {
-/* if (getCallingActivity() != null) {
- setResult(RESULT_OK, new Intent()
- .putExtra(Intent.EXTRA_PHONE_NUMBER, number)
- .putExtra(EXTRA_CONTACT_NAME, name));
- finish();
- }*/
-
- ((ContactPicked) getParent()).setAddressAndGoToDialer(number, name, photo);
- }
-
-
- protected abstract List extractPhones(String id);
- protected abstract Uri getPhotoUri(String id);
-
- // Hook
- protected List extractSipNumbers(String id) {
- return Collections.emptyList();
- }
-
- public abstract Cursor runQuery(CharSequence constraint);
-
-}
diff --git a/src/org/linphone/LinphonePreferencesSIPAccountActivity.java b/src/org/linphone/AccountPreferencesActivity.java
similarity index 98%
rename from src/org/linphone/LinphonePreferencesSIPAccountActivity.java
rename to src/org/linphone/AccountPreferencesActivity.java
index c61762e1d..813cf7846 100644
--- a/src/org/linphone/LinphonePreferencesSIPAccountActivity.java
+++ b/src/org/linphone/AccountPreferencesActivity.java
@@ -30,7 +30,10 @@ import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.text.InputType;
-public class LinphonePreferencesSIPAccountActivity extends PreferenceActivity {
+/**
+ * @author Sylvain Berfini
+ */
+public class AccountPreferencesActivity extends LinphonePreferencesActivity {
protected void onCreate(Bundle savedInstanceState)
{
@@ -123,7 +126,7 @@ public class LinphonePreferencesSIPAccountActivity extends PreferenceActivity {
editor.putInt(getString(R.string.pref_extra_accounts), nbAccounts - 1);
editor.commit();
- LinphonePreferencesSIPAccountActivity.this.finish();
+ AccountPreferencesActivity.this.finish();
return true;
}
});
diff --git a/src/org/linphone/AudioCallFragment.java b/src/org/linphone/AudioCallFragment.java
new file mode 100644
index 000000000..a97a29e67
--- /dev/null
+++ b/src/org/linphone/AudioCallFragment.java
@@ -0,0 +1,135 @@
+package org.linphone;
+/*
+AudioCallFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.core.LinphoneAddress;
+import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCall.State;
+import org.linphone.core.LinphoneCoreFactory;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class AudioCallFragment extends Fragment {
+ private static AudioCallFragment instance;
+ private LinearLayout callsList;
+ private LayoutInflater inflater;
+ private ViewGroup container;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ instance = this;
+ this.inflater = inflater;
+ this.container = container;
+
+ View view = inflater.inflate(R.layout.audio, container, false);
+ callsList = (LinearLayout) view.findViewById(R.id.calls);
+
+ return view;
+ }
+
+ private void displayCall(Resources resources, LinearLayout callView, LinphoneCall call, boolean first, boolean hide) {
+ String sipUri = call.getRemoteAddress().asStringUriOnly();
+ LinphoneAddress lAddress = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri);
+ Uri pictureUri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, callView.getContext().getContentResolver());
+
+ TextView contact = (TextView) callView.findViewById(R.id.contactNameOrNumber);
+ if (lAddress.getDisplayName() == null) {
+ if (resources.getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(sipUri)) {
+ contact.setText(LinphoneUtils.getUsernameFromAddress(sipUri));
+ } else {
+ contact.setText(sipUri);
+ }
+ } else {
+ contact.setText(lAddress.getDisplayName());
+ }
+
+ ImageView callState = (ImageView) callView.findViewById(R.id.callStatus);
+ if (call.getState() == State.Paused || call.getState() == State.PausedByRemote) {
+ callState.setImageResource(R.drawable.pause_default);
+ } else {
+ callState.setImageResource(R.drawable.play_default);
+ }
+
+ ImageView contactPicture = (ImageView) callView.findViewById(R.id.contactPicture);
+ if (pictureUri != null) {
+ LinphoneUtils.setImagePictureFromUri(callView.getContext(), contactPicture, Uri.parse(pictureUri.toString()), R.drawable.unknown_small);
+ }
+ if (hide) {
+ contactPicture.setVisibility(View.GONE);
+ }
+
+ if (first) {
+ callView.findViewById(R.id.row).setBackgroundResource(R.drawable.sel_call_first);
+ } else {
+ callView.findViewById(R.id.row).setBackgroundResource(R.drawable.sel_call);
+ }
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ InCallActivity.instance().bindAudioFragment(this);
+
+ // Just to be sure we have incall controls
+ InCallActivity.instance().setCallControlsVisibleAndRemoveCallbacks();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ // Add calls
+ refreshCallList(getResources());
+ }
+
+ /**
+ * @return null if not ready yet
+ */
+ public static AudioCallFragment instance() {
+ return instance;
+ }
+
+ public void refreshCallList(Resources resources) {
+ callsList.removeAllViews();
+ int callsNb = LinphoneManager.getLc().getCallsNb();
+ int index = 0;
+
+ for (LinphoneCall call : LinphoneManager.getLc().getCalls()) {
+ LinearLayout callView = (LinearLayout) inflater.inflate(R.layout.active_call, container, false);
+ displayCall(resources, callView, call, index == 0, index != callsNb - 1);
+ callsList.addView(callView);
+ index++;
+ }
+
+ callsList.invalidate();
+ }
+}
diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java
new file mode 100644
index 000000000..c2dc50499
--- /dev/null
+++ b/src/org/linphone/ChatFragment.java
@@ -0,0 +1,159 @@
+package org.linphone;
+/*
+ChatFragment.java
+Copyright (C) 2012 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.
+*/
+import java.util.List;
+
+import org.linphone.LinphoneSimpleListener.LinphoneOnMessageReceivedListener;
+import org.linphone.core.LinphoneAddress;
+import org.linphone.core.LinphoneChatRoom;
+import org.linphone.core.LinphoneCore;
+import org.linphone.ui.BubbleChat;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class ChatFragment extends Fragment implements OnClickListener, LinphoneOnMessageReceivedListener {
+ private LinphoneChatRoom chatRoom;
+ private String sipUri;
+ private EditText message;
+ private RelativeLayout messagesLayout;
+ private ScrollView messagesScrollView;
+ private int previousMessageID;
+ private Handler mHandler = new Handler();
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ sipUri = getArguments().getString("SipUri");
+ String name = getArguments().getString("DisplayName");
+ String pictureUri = getArguments().getString("PictureUri");
+
+ View view = inflater.inflate(R.layout.chat, container, false);
+
+ TextView contactName = (TextView) view.findViewById(R.id.contactName);
+ if (name == null && getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(sipUri)) {
+ contactName.setText(LinphoneUtils.getUsernameFromAddress(sipUri));
+ } else if (name == null) {
+ contactName.setText(sipUri);
+ }
+ else {
+ contactName.setText(name);
+ }
+
+ ImageView contactPicture = (ImageView) view.findViewById(R.id.contactPicture);
+ if (pictureUri != null) {
+ LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture, Uri.parse(pictureUri), R.drawable.unknown_small);
+ }
+
+ ImageView sendMessage = (ImageView) view.findViewById(R.id.sendMessage);
+ sendMessage.setOnClickListener(this);
+ message = (EditText) view.findViewById(R.id.message);
+
+ messagesLayout = (RelativeLayout) view.findViewById(R.id.messages);
+ List messagesList = LinphoneActivity.instance().getChatMessages(sipUri);
+
+ messagesScrollView = (ScrollView) view.findViewById(R.id.chatScrollView);
+ messagesScrollView.post(new Runnable() {
+ @Override
+ public void run() {
+ scrollToEnd();
+ }
+ });
+
+ previousMessageID = -1;
+ for (ChatMessage msg : messagesList) {
+ displayMessage(msg.getId(), msg.getMessage(), msg.getTimestamp(), msg.isIncoming(), messagesLayout);
+ }
+
+ LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
+ if (lc != null)
+ chatRoom = lc.createChatRoom(sipUri);
+
+ return view;
+ }
+
+ private void displayMessage(final int id, final String message, final String time, final boolean isIncoming, final RelativeLayout layout) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ BubbleChat bubble = new BubbleChat(layout.getContext(), id, message, time, isIncoming, previousMessageID);
+ previousMessageID = id;
+ layout.addView(bubble.getView());
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().selectMenu(FragmentsAvailable.CHAT);
+ LinphoneActivity.instance().updateChatFragment(this);
+ }
+ scrollToEnd();
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (chatRoom != null && message != null) {
+ String messageToSend = message.getText().toString();
+ message.setText("");
+
+ chatRoom.sendMessage(messageToSend);
+
+ if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().onMessageSent(sipUri, messageToSend);
+ }
+
+ displayMessage(previousMessageID + 1, messageToSend, getString(R.string.now_date_format), false, messagesLayout);
+ scrollToEnd();
+ }
+ }
+
+ private void scrollToEnd() {
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ messagesScrollView.fullScroll(View.FOCUS_DOWN);
+ }
+ }, 100);
+ }
+
+ @Override
+ public void onMessageReceived(LinphoneAddress from, String message) {
+ if (from.asStringUriOnly().equals(sipUri)) {
+ displayMessage(previousMessageID + 1, message, getString(R.string.now_date_format), true, messagesLayout);
+ scrollToEnd();
+ }
+ }
+}
diff --git a/src/org/linphone/ChatListFragment.java b/src/org/linphone/ChatListFragment.java
new file mode 100644
index 000000000..2332cc7a6
--- /dev/null
+++ b/src/org/linphone/ChatListFragment.java
@@ -0,0 +1,170 @@
+package org.linphone;
+/*
+ChatListFragment.java
+Copyright (C) 2012 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.
+*/
+import java.util.List;
+
+import org.linphone.core.LinphoneAddress;
+import org.linphone.core.LinphoneCoreFactory;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class ChatListFragment extends Fragment implements OnClickListener, OnItemClickListener {
+ private LayoutInflater mInflater;
+ private List mConversations;
+ private ListView chatList;
+ private ImageView edit, ok, newDiscussion;
+ private boolean isEditMode = false;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mInflater = inflater;
+
+ View view = inflater.inflate(R.layout.chatlist, container, false);
+ chatList = (ListView) view.findViewById(R.id.chatList);
+ chatList.setOnItemClickListener(this);
+
+ edit = (ImageView) view.findViewById(R.id.edit);
+ edit.setOnClickListener(this);
+ newDiscussion = (ImageView) view.findViewById(R.id.newDiscussion);
+ newDiscussion.setOnClickListener(this);
+ ok = (ImageView) view.findViewById(R.id.ok);
+ ok.setOnClickListener(this);
+
+ return view;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (LinphoneActivity.isInstanciated())
+ LinphoneActivity.instance().selectMenu(FragmentsAvailable.CHATLIST);
+
+ mConversations = LinphoneActivity.instance().getChatList();
+ chatList.setAdapter(new ChatListAdapter());
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (id == R.id.ok) {
+ edit.setVisibility(View.VISIBLE);
+ ok.setVisibility(View.GONE);
+ isEditMode = false;
+ chatList.setAdapter(new ChatListAdapter());
+ }
+ else if (id == R.id.edit) {
+ edit.setVisibility(View.GONE);
+ ok.setVisibility(View.VISIBLE);
+ isEditMode = true;
+ chatList.setAdapter(new ChatListAdapter());
+ }
+ else if (id == R.id.newDiscussion) {
+ //TODO : Create a new conversation
+ }
+ }
+
+ @Override
+ public void onItemClick(AdapterView> adapter, View view, int position, long id) {
+ String sipUri = (String) view.getTag();
+
+ if (LinphoneActivity.isInstanciated() && !isEditMode) {
+ LinphoneActivity.instance().displayChat(sipUri);
+ } else if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().removeFromChatList(sipUri);
+ mConversations = LinphoneActivity.instance().getChatList();
+ chatList.setAdapter(new ChatListAdapter());
+ }
+ }
+
+ class ChatListAdapter extends BaseAdapter {
+ ChatListAdapter() {
+ }
+
+ public int getCount() {
+ return mConversations.size();
+ }
+
+ public Object getItem(int position) {
+ return position;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = null;
+
+ if (convertView != null) {
+ view = convertView;
+ } else {
+ view = mInflater.inflate(R.layout.chatlist_cell, parent, false);
+
+ }
+ String contact = mConversations.get(position);
+ view.setTag(contact);
+
+ LinphoneAddress address = LinphoneCoreFactory.instance().createLinphoneAddress(contact);
+ LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, view.getContext().getContentResolver());
+
+ TextView sipUri = (TextView) view.findViewById(R.id.sipUri);
+
+ if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(address.getDisplayName())) {
+ address.setDisplayName(LinphoneUtils.getUsernameFromAddress(address.getDisplayName()));
+ } else if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(contact)) {
+ contact = LinphoneUtils.getUsernameFromAddress(contact);
+ }
+
+ sipUri.setText(address.getDisplayName() == null ? contact : address.getDisplayName());
+
+ ImageView delete, detail;
+ delete = (ImageView) view.findViewById(R.id.delete);
+ detail = (ImageView) view.findViewById(R.id.detail);
+
+ if (isEditMode) {
+ delete.setVisibility(View.VISIBLE);
+ detail.setVisibility(View.GONE);
+ } else {
+ delete.setVisibility(View.GONE);
+ detail.setVisibility(View.VISIBLE);
+ }
+
+ return view;
+ }
+ }
+}
+
+
diff --git a/src/org/linphone/ChatMessage.java b/src/org/linphone/ChatMessage.java
new file mode 100644
index 000000000..1b6bc42b3
--- /dev/null
+++ b/src/org/linphone/ChatMessage.java
@@ -0,0 +1,65 @@
+package org.linphone;
+/*
+ChatMessage.java
+Copyright (C) 2012 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.
+*/
+
+/**
+ * @author Sylvain Berfini
+ */
+public class ChatMessage {
+ private String message;
+ private String timestamp;
+ private boolean incoming;
+ private int id;
+
+ public ChatMessage(int id, String message, String timestamp, boolean incoming) {
+ super();
+ this.id = id;
+ this.message = message;
+ this.timestamp = timestamp;
+ this.incoming = incoming;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(String timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public boolean isIncoming() {
+ return incoming;
+ }
+
+ public void setIncoming(boolean incoming) {
+ this.incoming = incoming;
+ }
+}
diff --git a/src/org/linphone/ChatStorage.java b/src/org/linphone/ChatStorage.java
new file mode 100644
index 000000000..7e43de391
--- /dev/null
+++ b/src/org/linphone/ChatStorage.java
@@ -0,0 +1,125 @@
+package org.linphone;
+/*
+ChatStorage.java
+Copyright (C) 2012 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.
+*/
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class ChatStorage {
+ private Context context;
+ private SQLiteDatabase db;
+ private static final String TABLE_NAME = "chat";
+
+ public ChatStorage(Context c) {
+ context = c;
+ ChatHelper chatHelper = new ChatHelper(context);
+ db = chatHelper.getWritableDatabase();
+ }
+
+ public void close() {
+ db.close();
+ }
+
+ public void saveMessage(String from, String to, String message) {
+ ContentValues values = new ContentValues();
+ values.put("sender", from);
+ values.put("receiver", to);
+ values.put("message", message);
+ values.put("time", System.currentTimeMillis());
+ db.insert(TABLE_NAME, null, values);
+ }
+
+ public List getMessages(String correspondent) {
+ List chatMessages = new ArrayList();
+
+ Cursor c = db.query(TABLE_NAME, null, "receiver LIKE \"" + correspondent +
+ "\" OR sender LIKE \"" + correspondent + "\"", null, null, null, "id ASC");
+
+ while (c.moveToNext()) {
+ String to, message, timestamp;
+ int id = c.getInt(c.getColumnIndex("id"));
+ to = c.getString(c.getColumnIndex("receiver"));
+ message = c.getString(c.getColumnIndex("message"));
+ timestamp = c.getString(c.getColumnIndex("time"));
+
+ ChatMessage chatMessage = new ChatMessage(id, message, timestamp, to.equals(""));
+ chatMessages.add(chatMessage);
+ }
+
+ return chatMessages;
+ }
+
+ public void removeDiscussion(String correspondent) {
+ db.delete(TABLE_NAME, "sender LIKE \"" + correspondent + "\"", null);
+ db.delete(TABLE_NAME, "receiver LIKE \"" + correspondent + "\"", null);
+ }
+
+ public ArrayList getChatList() {
+ ArrayList chatList = new ArrayList();
+
+ Cursor c = db.query(TABLE_NAME, null, null, null, null, null, "id DESC");
+ while (c.moveToNext()) {
+ String from, to;
+ from = c.getString(c.getColumnIndex("sender"));
+ to = c.getString(c.getColumnIndex("receiver"));
+
+ if (from.equals("") && !to.equals("")) {
+ if (!chatList.contains(to)) {
+ chatList.add(to);
+ }
+ }
+ else if (!from.equals("") && to.equals(""))
+ {
+ if (!chatList.contains(from)) {
+ chatList.add(from);
+ }
+ }
+ }
+
+ return chatList;
+ }
+
+ class ChatHelper extends SQLiteOpenHelper {
+
+ private static final int DATABASE_VERSION = 1;
+ private static final String DATABASE_NAME = "linphone-android";
+
+ ChatHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, sender TEXT NOT NULL, receiver TEXT NOT NULL, message TEXT NOT NULL, time NUMERIC);");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/org/linphone/ConferenceDetailsActivity.java b/src/org/linphone/ConferenceDetailsActivity.java
deleted file mode 100644
index f9ebc4763..000000000
--- a/src/org/linphone/ConferenceDetailsActivity.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-ConferenceActivity.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.List;
-
-import org.linphone.core.LinphoneAddress;
-import org.linphone.core.LinphoneCall;
-import org.linphone.mediastream.Version;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.OnClickListener;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-/**
- * List participants of a conference call.
- *
- * @author Guillaume Beraudo
- *
- */
-public class ConferenceDetailsActivity extends AbstractCalleesActivity {
-
- public static boolean active;
- @Override protected void setActive(boolean a) {active = a;}
- @Override protected boolean isActive() {return active;}
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- if (finishIfAutoRestartAfterACrash(savedInstanceState)) {
- return;
- }
- setContentView(R.layout.conference_details_layout);
- View v=findViewById(R.id.incallHang);
- v.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- lc().terminateConference();
- }
- });
- super.onCreate(savedInstanceState);
- }
-
- protected CalleeListAdapter createCalleeListAdapter() {
- return new ConfListAdapter();
- }
-
- private class ConfListAdapter extends CalleeListAdapter {
- @Override
- public View getView(int position, View v, ViewGroup parent) {
- if (v == null) {
- if (Version.sdkAboveOrEqual(Version.API06_ECLAIR_201)) {
- v = getLayoutInflater().inflate(R.layout.conf_callee, null);
- } else {
- v = getLayoutInflater().inflate(R.layout.conf_callee_older_devices, null);
- }
- }
-
- final LinphoneCall call = getItem(position);
- LinphoneAddress address = call.getRemoteAddress();
- final String mainText = getCalleeDisplayOrUserName(address);
- ((TextView) v.findViewById(R.id.name)).setText(mainText);
- ((TextView) v.findViewById(R.id.address)).setText("");
-
- v.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- if (lc().soundResourcesLocked()) {
- return;
- }
- View content = getLayoutInflater().inflate(R.layout.conf_details_participant_choices_dialog, null);
- Dialog dialog = new AlertDialog.Builder(ConferenceDetailsActivity.this).setView(content).create();
- OnClickListener l = new CallActionListener(call, dialog);
- enableView(content, R.id.remove_from_conference, l, true);
- enableView(content, R.id.terminate_call, l, true);
- dialog.show();
- }
- });
-
- setVisibility(v, R.id.callee_status_qos, true);
-
- // May be greatly sped up using a drawable cache
- ImageView pictureView = (ImageView) v.findViewById(R.id.picture);
- setCalleePicture(pictureView, address);
-
- registerCallDurationTimer(v, call);
- registerCallQualityListener(v, call);
- registerCallSpeakerListener();
-
- return v;
- }
-
- }
-
- private class CallActionListener implements OnClickListener {
- private LinphoneCall call;
- private Dialog dialog;
- public CallActionListener(LinphoneCall call, Dialog dialog) {
- this.call = call;
- this.dialog = dialog;
- }
- public void onClick(View v) {
- int id = v.getId();
- if (id == R.id.terminate_call) {
- lc().terminateCall(call);
- }
- else if (id == R.id.remove_from_conference) {
- lc().removeFromConference(call);
- if (LinphoneUtils.countConferenceCalls(lc()) == 0) {
- finish();
- }
- }
- else {
- throw new RuntimeException("unknown id " + v.getId());
- }
- if (dialog != null) dialog.dismiss();
- }
- }
-
-
- @Override
- protected List updateSpecificCallsList() {
- return LinphoneUtils.getLinphoneCallsInConf(lc());
- }
-
-}
\ No newline at end of file
diff --git a/src/org/linphone/Contact.java b/src/org/linphone/Contact.java
new file mode 100644
index 000000000..55d16a684
--- /dev/null
+++ b/src/org/linphone/Contact.java
@@ -0,0 +1,84 @@
+package org.linphone;
+/*
+Contact.java
+Copyright (C) 2012 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.
+*/
+import java.io.Serializable;
+import java.util.List;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class Contact implements Serializable {
+ private static final long serialVersionUID = 3790717505065723499L;
+
+ private String id;
+ private String name;
+ private transient Uri photoUri;
+ private transient Bitmap photo;
+ private List numerosOrAddresses;
+
+ public Contact(String id, String name) {
+ super();
+ this.id = id;
+ this.name = name;
+ this.photoUri = null;
+ }
+
+ public Contact(String id, String name, Uri photo) {
+ super();
+ this.id = id;
+ this.name = name;
+ this.photoUri = photo;
+ this.photo = null;
+ }
+
+ public Contact(String id, String name, Uri photo, Bitmap picture) {
+ super();
+ this.id = id;
+ this.name = name;
+ this.photoUri = photo;
+ this.photo = picture;
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Uri getPhotoUri() {
+ return photoUri;
+ }
+
+ public Bitmap getPhoto() {
+ return photo;
+ }
+
+ public List getNumerosOrAddresses() {
+ return numerosOrAddresses;
+ }
+
+ public void setNumerosOrAddresses(List numerosOrAddresses) {
+ this.numerosOrAddresses = numerosOrAddresses;
+ }
+}
diff --git a/src/org/linphone/ContactFragment.java b/src/org/linphone/ContactFragment.java
new file mode 100644
index 000000000..90af9eccc
--- /dev/null
+++ b/src/org/linphone/ContactFragment.java
@@ -0,0 +1,101 @@
+package org.linphone;
+/*
+ContactFragment.java
+Copyright (C) 2012 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.
+*/
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TableLayout;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class ContactFragment extends Fragment {
+ private Contact contact;
+ private OnClickListener dialListener, chatListener;
+
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ contact = (Contact) getArguments().getSerializable("Contact");
+ View view = inflater.inflate(R.layout.contact, container, false);
+
+ ImageView contactPicture = (ImageView) view.findViewById(R.id.contactPicture);
+ if (contact.getPhoto() != null) {
+ LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture, contact.getPhotoUri(), R.drawable.unknown_small);
+ }
+
+ chatListener = getChatListener();
+ dialListener = getDialListener();
+
+ TextView contactName = (TextView) view.findViewById(R.id.contactName);
+ contactName.setText(contact.getName());
+
+ TableLayout controls = (TableLayout) view.findViewById(R.id.controls);
+
+ for (String numberOrAddress : contact.getNumerosOrAddresses()) {
+ View v = inflater.inflate(R.layout.contact_control_row, null);
+
+ ((TextView) v.findViewById(R.id.numeroOrAddress)).setText(numberOrAddress);
+
+ v.findViewById(R.id.dial).setOnClickListener(dialListener);
+ v.findViewById(R.id.dial).setTag(numberOrAddress);
+
+ if (LinphoneUtils.isSipAddress(numberOrAddress)) {
+ v.findViewById(R.id.chat).setOnClickListener(chatListener);
+ v.findViewById(R.id.chat).setTag(numberOrAddress);
+ } else {
+ v.findViewById(R.id.chat).setVisibility(View.INVISIBLE);
+ }
+
+ controls.addView(v);
+ }
+
+ return view;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACT);
+ }
+ }
+
+ public OnClickListener getDialListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LinphoneActivity.instance().setAddresGoToDialerAndCall(v.getTag().toString(), contact.getName(), contact.getPhotoUri());
+ }
+ };
+ }
+
+ public OnClickListener getChatListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LinphoneActivity.instance().displayChat(v.getTag().toString());
+ }
+ };
+ }
+}
diff --git a/src/org/linphone/ContactHelper.java b/src/org/linphone/ContactHelper.java
index e47add169..164ced4f1 100644
--- a/src/org/linphone/ContactHelper.java
+++ b/src/org/linphone/ContactHelper.java
@@ -18,23 +18,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone;
+import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneAddress;
import org.linphone.mediastream.Version;
+import org.linphone.ui.AddressText;
import android.content.ContentResolver;
import android.content.ContentUris;
+import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
public final class ContactHelper {
-
private String username;
private String domain;
private ContentResolver resolver;
-
private Uri foundPhotoUri;
public Uri getUri() {
return foundPhotoUri;
@@ -55,7 +57,7 @@ public final class ContactHelper {
public boolean query() {
boolean succeeded;
- if (Version.sdkAboveOrEqual(Version.API06_ECLAIR_201)) {
+ if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
ContactHelperNew helper = new ContactHelperNew();
succeeded = helper.queryNewContactAPI();
} else {
@@ -67,7 +69,17 @@ public final class ContactHelper {
return succeeded;
}
-
+ public static Intent prepareAddContactIntent(AddressText address) {
+ return Compatibility.prepareAddContactIntent(address.getDisplayedName(), address.getText().toString());
+ }
+
+ public static Intent prepareEditContactIntent(int id) {
+ Intent intent = new Intent(Intent.ACTION_EDIT, Contacts.CONTENT_URI);
+ Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
+ intent.setData(contactUri);
+
+ return intent;
+ }
public static boolean testPhotoUri(Cursor c) {
if (c == null) return false;
@@ -96,7 +108,6 @@ public final class ContactHelper {
return testPhotoUriAndCloseCursor(cursor);
}
-
// OLD API
@SuppressWarnings("deprecation")
private final boolean queryOldContactAPI() {
@@ -128,22 +139,10 @@ public final class ContactHelper {
// END OLD API
-
-
-
-
-
-
-
-
-
-
// START NEW CONTACT API
private class ContactHelperNew {
-
-
-
+
private final boolean checkPhotosUris(ContentResolver resolver, Cursor c, String idCol, String nameCol) {
if (c == null) return false;
while (c.moveToNext()) {
@@ -175,6 +174,24 @@ public final class ContactHelper {
String[] projection = {
android.provider.ContactsContract.Data.CONTACT_ID,
android.provider.ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME};
+
+ // Then using custom SIP field
+ if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
+ String selection = new StringBuilder()
+ .append(android.provider.ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS)
+ .append(" = ? AND ")
+ .append(android.provider.ContactsContract.Data.MIMETYPE)
+ .append(" = '")
+ .append(android.provider.ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
+ .append("'")
+ .toString();
+ Cursor c = resolver.query(uri, projection, selection, new String[] {sipUri}, null);
+ boolean valid = checkPhotosUris(resolver, c,
+ android.provider.ContactsContract.Data.CONTACT_ID,
+ android.provider.ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
+ if (valid) return true;
+ }
+
String selection = new StringBuilder()
.append(android.provider.ContactsContract.CommonDataKinds.Im.DATA).append(" = ? AND ")
.append(android.provider.ContactsContract.Data.MIMETYPE)
@@ -189,24 +206,6 @@ public final class ContactHelper {
android.provider.ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
if (valid) return true;
-
- // Then using custom SIP field
- if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
- selection = new StringBuilder()
- .append(android.provider.ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS)
- .append(" = ? AND ")
- .append(android.provider.ContactsContract.Data.MIMETYPE)
- .append(" = '")
- .append(android.provider.ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
- .append("'")
- .toString();
- c = resolver.query(uri, projection, selection, new String[] {sipUri}, null);
- valid = checkPhotosUris(resolver, c,
- android.provider.ContactsContract.Data.CONTACT_ID,
- android.provider.ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
- if (valid) return true;
- }
-
// Finally using phone number
String normalizedNumber = PhoneNumberUtils.getStrippedReversed(username);
if (TextUtils.isEmpty(normalizedNumber)) {
@@ -244,14 +243,5 @@ public final class ContactHelper {
c.close();
return false;
}
-
-
}
-
-
-
-
-
-
-
-}
+}
\ No newline at end of file
diff --git a/src/org/linphone/ContactPickerActivityNew.java b/src/org/linphone/ContactPickerActivityNew.java
deleted file mode 100644
index 89132ab10..000000000
--- a/src/org/linphone/ContactPickerActivityNew.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
-ContactPickerActivity.java
-Copyright (C) 2010 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.List;
-
-import org.linphone.mediastream.Version;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.text.TextUtils;
-
-
-/**
- * Activity for retrieving a phone number / SIP address to call.
- *
- *
- * The cinematic is:
- *
- * - Select contact (either through native or custom way)
- * - Select phone number or SIP address
- *
- Back to dialer
- *
- *
- * @author Guillaume Beraudo
- *
- */
-public class ContactPickerActivityNew extends AbstractContactPickerActivityNew {
-
-
-
- @Override
- public Uri getPhotoUri(String id) {
- return retrievePhotoUriAndSetDisplayName(getContentResolver(), Long.parseLong(id));
- }
-
- private static Uri retrievePhotoUriAndSetDisplayName(ContentResolver resolver, long id) {
- Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
- Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
- if (photoUri == null) {
- return null;
- }
- if (ContactHelper.testPhotoUri(resolver, photoUri, ContactsContract.CommonDataKinds.Photo.PHOTO)) {
- return photoUri;
- }
- return null;
- }
-
- protected List extractPhones(String id) {
- List list = new ArrayList();
- Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
- String[] projection = {ContactsContract.CommonDataKinds.Phone.NUMBER};
- String selection = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?";
- String[] selArgs = new String[] {id};
- Cursor c = this.getContentResolver().query(uri, projection, selection, selArgs, null);
-
- int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
-
- while (c.moveToNext()) {
- list.add(c.getString(nbId));
- }
-
- c.close();
-
- return list;
- }
-
- protected List extractSipNumbers(String id) {
- List list = new ArrayList();
- Uri uri = ContactsContract.Data.CONTENT_URI;
- String[] projection = {ContactsContract.CommonDataKinds.Im.DATA};
- String selection = new StringBuilder()
- .append(ContactsContract.Data.CONTACT_ID).append(" = ? AND ")
- .append(ContactsContract.Data.MIMETYPE).append(" = '")
- .append(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
- .append("' AND lower(")
- .append(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL)
- .append(") = 'sip'")
- .toString();
- Cursor c = getContentResolver().query(uri, projection, selection, new String[]{id}, null);
-
- int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA);
- while (c.moveToNext()) {
- list.add("sip:" + c.getString(nbId));
- }
- c.close();
-
-
- // Using the SIP contact field added in SDK 9
- if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
- selection = new StringBuilder()
- .append(ContactsContract.Data.CONTACT_ID)
- .append(" = ? AND ")
- .append(ContactsContract.Data.MIMETYPE)
- .append(" = '")
- .append(ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
- .append("'")
- .toString();
- projection = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS};
- c = this.getContentResolver().query(uri, projection, selection, new String[]{id}, null);
-
- nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
- while (c.moveToNext()) {
- list.add("sip:" + c.getString(nbId));
- }
- c.close();
- }
-
- return list;
- }
-
-
- @Override
- protected void onNewIntent(Intent intent) {
- // Launch the native contact picker here in spite of onResume
- // in order to avoid a loop that sometime occurs on HTC phones.
- if (useNativePicker) {
- Uri uri = ContactsContract.Contacts.CONTENT_URI;
- //ContactsContract.CommonDataKinds.Phone.CONTENT_URI
- startActivityForResult(new Intent(Intent.ACTION_PICK, uri), 0);
- }
- super.onNewIntent(intent);
- }
-
- protected void onActivityResult(int reqCode, int resultCode, Intent intent) {
- // If using native picker
- if (reqCode == 0) {
- if (resultCode == RESULT_OK) {
- String id = intent.getData().getLastPathSegment();
- String contactName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
- if (contactName == null) {
- contactName = retrieveContactName(id);
- }
- choosePhoneNumberAndDial(contactName, id);
- }
- }
-
- ((ContactPicked) getParent()).goToDialer();
- }
-
-
- private String retrieveContactName(String id) {
- //Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
- Uri uri = ContactsContract.Contacts.CONTENT_URI;
- String[] projection = new String[] {ContactsContract.Contacts.DISPLAY_NAME};
- String selection = ContactsContract.Contacts._ID + " = ?";
- String[] selArgs = new String[] {id};
- Cursor c = this.getContentResolver().query(uri, projection, selection, selArgs, null);
-
- String name = "";
- if (c.moveToFirst()) {
- name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
- }
- c.close();
-
- return name;
- }
-
-
-
- public Cursor runQuery(CharSequence constraint) {
- // Run query
- Uri uri = ContactsContract.Contacts.CONTENT_URI;
- String[] projection = new String[] {
- ContactsContract.Contacts._ID,
- ContactsContract.Contacts.DISPLAY_NAME
- };
- String selection =
- ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1' and "
- + ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1'";
- String[] selectionArgs = null;
- if (!TextUtils.isEmpty(constraint)) {
- // FIXME SQL injection - Android doesn't accept '?' in like queries
- selection += " and " + ContactsContract.Contacts.DISPLAY_NAME + " like '%"+mcontactFilter.getText()+"%'";
- }
-
- String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
-
- return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
- }
-
-
-}
diff --git a/src/org/linphone/ContactPickerActivityOld.java b/src/org/linphone/ContactPickerActivityOld.java
deleted file mode 100644
index b136aea2c..000000000
--- a/src/org/linphone/ContactPickerActivityOld.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
-ContactPickerActivity.java
-Copyright (C) 2010 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 android.app.Activity;
-import android.content.ContentUris;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
-
-@SuppressWarnings("deprecation")
-public class ContactPickerActivityOld extends Activity {
- static final int PICK_CONTACT_REQUEST = 0;
- static final int PICK_PHONE_NUMBER_REQUEST = 1;
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- onNewIntent(getIntent());
- }
-
-
- @Override
- protected void onNewIntent(Intent intent) {
- // Launch the native contact picker here in spite of onResume
- // in order to avoid a loop that sometime occurs on HTC phones.
- Uri uri = Contacts.Phones.CONTENT_URI;
- startActivityForResult(new Intent(Intent.ACTION_PICK,uri), PICK_CONTACT_REQUEST);
- super.onNewIntent(intent);
- }
-
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- if (requestCode == PICK_CONTACT_REQUEST) {
- if (resultCode == RESULT_OK) {
- String lColumns[] = new String[] { People._ID, People.NAME, People.NUMBER };
-
- Cursor lCur = managedQuery(data.getData(), lColumns, // Which columns to return
- null, // WHERE clause; which rows to return(all rows)
- null, // WHERE clause selection arguments (none)
- null // Order-by clause (ascending by name)
-
- );
- if (lCur.moveToFirst()) {
- String lName = lCur.getString(lCur.getColumnIndex(People.NAME));
- String lPhoneNo = lCur.getString(lCur.getColumnIndex(People.NUMBER));
- long id = lCur.getLong(lCur.getColumnIndex(People._ID));
- Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, id);
- Uri pictureUri = Uri.withAppendedPath(personUri, Contacts.Photos.CONTENT_DIRECTORY);
- if (!ContactHelper.testPhotoUri(getContentResolver(), pictureUri, android.provider.Contacts.Photos.DATA)) {
- pictureUri = null;
- }
- ((ContactPicked) getParent()).setAddressAndGoToDialer(lPhoneNo, lName, pictureUri);
- }
- }
-
- ((ContactPicked) getParent()).goToDialer();
- }
- }
-
-}
diff --git a/src/org/linphone/ContactsFragment.java b/src/org/linphone/ContactsFragment.java
new file mode 100644
index 000000000..59af02d20
--- /dev/null
+++ b/src/org/linphone/ContactsFragment.java
@@ -0,0 +1,260 @@
+package org.linphone;
+/*
+ContactsFragment.java
+Copyright (C) 2012 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.
+*/
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.linphone.compatibility.Compatibility;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.support.v4.app.Fragment;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AlphabetIndexer;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.SectionIndexer;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class ContactsFragment extends Fragment implements OnClickListener, OnItemClickListener {
+ private LayoutInflater mInflater;
+ private ListView contactsList;
+ private ImageView allContacts, linphoneContacts, newContact;
+ private boolean onlyDisplayLinphoneCalls;
+ private int lastKnownPosition;
+ private Cursor cursor;
+ private List contacts;
+ private Thread contactsHandler;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mInflater = inflater;
+ View view = inflater.inflate(R.layout.contacts_list, container, false);
+
+ contactsList = (ListView) view.findViewById(R.id.contactsList);
+ contactsList.setOnItemClickListener(this);
+
+ allContacts = (ImageView) view.findViewById(R.id.allContacts);
+ allContacts.setOnClickListener(this);
+ linphoneContacts = (ImageView) view.findViewById(R.id.linphoneContacts);
+ linphoneContacts.setOnClickListener(this);
+ allContacts.setEnabled(false);
+ onlyDisplayLinphoneCalls = false;
+ newContact = (ImageView) view.findViewById(R.id.newContact);
+ newContact.setOnClickListener(this);
+ newContact.setEnabled(!LinphoneActivity.instance().isInCallLayout());
+
+ return view;
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (id == R.id.allContacts) {
+ allContacts.setEnabled(false);
+ linphoneContacts.setEnabled(true);
+ onlyDisplayLinphoneCalls = false;
+ }
+ else if (id == R.id.linphoneContacts) {
+ allContacts.setEnabled(true);
+ linphoneContacts.setEnabled(false);
+ onlyDisplayLinphoneCalls = true;
+ }
+ else if (id == R.id.newContact) {
+ Intent intent = Compatibility.prepareAddContactIntent(null, null);
+ startActivity(intent);
+ }
+ }
+
+ @Override
+ public void onItemClick(AdapterView> adapter, View view, int position, long id) {
+ lastKnownPosition = contactsList.getFirstVisiblePosition();
+ LinphoneActivity.instance().displayContact((Contact) adapter.getItemAtPosition(position));
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ cursor = Compatibility.getContactsCursor(getActivity().getContentResolver());
+ contactsHandler = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ contacts = new ArrayList();
+ for (int i = 0; i < cursor.getCount(); i++) {
+ Contact contact = getContact(i);
+ contacts.add(contact);
+ }
+ }
+ });
+ contactsHandler.start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACTS);
+ }
+
+ if (contactsList.getAdapter() == null) {
+ contactsList.setAdapter(new ContactsListAdapter());
+ contactsList.setFastScrollEnabled(true);
+ }
+
+ contactsList.setSelectionFromTop(lastKnownPosition, 0);
+ }
+
+ @Override
+ public void onPause() {
+ contactsHandler.interrupt();
+ super.onPause();
+ }
+
+ private Contact getContact(int position) {
+ try {
+ cursor.moveToFirst();
+ boolean success = cursor.move(position);
+ if (!success)
+ return null;
+
+ String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
+ String name = Compatibility.getContactDisplayName(cursor);
+ Uri photo = Compatibility.getContactPictureUri(cursor, id);
+ InputStream input = Compatibility.getContactPictureInputStream(getActivity().getContentResolver(), id);
+
+ Contact contact;
+ if (input == null) {
+ contact = new Contact(id, name);
+ }
+ else {
+ contact = new Contact(id, name, photo, BitmapFactory.decodeStream(input));
+ }
+
+ contact.setNumerosOrAddresses(Compatibility.extractContactNumbersAndAddresses(contact.getID(), getActivity().getContentResolver()));
+
+ return contact;
+ } catch (Exception e) {
+
+ }
+ return null;
+ }
+
+ class ContactsListAdapter extends BaseAdapter implements SectionIndexer {
+ private AlphabetIndexer indexer;
+ private int margin;
+ private Bitmap bitmapUnknown;
+
+ ContactsListAdapter() {
+ indexer = new AlphabetIndexer(cursor, Compatibility.getCursorDisplayNameColumnIndex(cursor), " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics());
+ bitmapUnknown = BitmapFactory.decodeResource(getResources(), R.drawable.unknown_small);
+ }
+
+ public int getCount() {
+ return cursor.getCount();
+ }
+
+ public Object getItem(int position) {
+ if (position >= contacts.size()) {
+ return getContact(position);
+ } else {
+ return contacts.get(position);
+ }
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = null;
+
+ if (convertView != null) {
+ view = convertView;
+ } else {
+ view = mInflater.inflate(R.layout.contact_cell, parent, false);
+ }
+
+ Contact contact = null;
+ do {
+ contact = (Contact) getItem(position);
+ } while (contact == null);
+
+ TextView name = (TextView) view.findViewById(R.id.name);
+ name.setText(contact.getName());
+
+ TextView separator = (TextView) view.findViewById(R.id.separator);
+ LinearLayout layout = (LinearLayout) view.findViewById(R.id.layout);
+ if (getPositionForSection(getSectionForPosition(position)) != position) {
+ separator.setVisibility(View.GONE);
+ layout.setPadding(0, margin, 0, margin);
+ } else {
+ separator.setVisibility(View.VISIBLE);
+ separator.setText(String.valueOf(contact.getName().charAt(0)));
+ layout.setPadding(0, 0, 0, margin);
+ }
+
+ ImageView icon = (ImageView) view.findViewById(R.id.icon);
+ if (contact.getPhoto() != null) {
+ icon.setImageBitmap(contact.getPhoto());
+ } else if (contact.getPhotoUri() != null) {
+ icon.setImageURI(contact.getPhotoUri());
+ } else {
+ icon.setImageBitmap(bitmapUnknown);
+ }
+
+ return view;
+ }
+
+ @Override
+ public int getPositionForSection(int section) {
+ return indexer.getPositionForSection(section);
+ }
+
+ @Override
+ public int getSectionForPosition(int position) {
+ return indexer.getSectionForPosition(position);
+ }
+
+ @Override
+ public Object[] getSections() {
+ return indexer.getSections();
+ }
+ }
+}
diff --git a/src/org/linphone/DialerActivity.java b/src/org/linphone/DialerActivity.java
deleted file mode 100644
index 0c9b6d255..000000000
--- a/src/org/linphone/DialerActivity.java
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
-DialerActivity.java
-Copyright (C) 2010 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.HashMap;
-
-import org.linphone.LinphoneService.LinphoneGuiListener;
-import org.linphone.core.LinphoneCall;
-import org.linphone.core.LinphoneCall.State;
-import org.linphone.core.LinphoneCore.RegistrationState;
-import org.linphone.core.LinphoneCoreException;
-import org.linphone.core.LinphoneProxyConfig;
-import org.linphone.core.Log;
-import org.linphone.mediastream.Version;
-import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
-import org.linphone.ui.AddressAware;
-import org.linphone.ui.AddressText;
-import org.linphone.ui.CallButton;
-import org.linphone.ui.CameraView;
-import org.linphone.ui.EraseButton;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.hardware.Camera;
-import android.hardware.Camera.CameraInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.WindowManager;
-import android.view.View.OnClickListener;
-import android.widget.Adapter;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.SimpleAdapter;
-import android.widget.SlidingDrawer;
-import android.widget.SlidingDrawer.OnDrawerScrollListener;
-import android.widget.TextView;
-import android.widget.Toast;
-
-/**
- *
- * Dialer and main activity of Linphone Android.
- *
- * Roles are:
- * - Display the numpad, call/accept, address buttons
- * - Define preferences through the menu
- * - React to bad preference / no account set
- * - Manage first launch
- *
- *
- */
-public class DialerActivity extends Activity implements LinphoneGuiListener {
-
- private TextView mStatus;
-
- private AddressText mAddress;
- private CallButton mCall;
- private Button mBack, mAddCall, mSwitchCamera;
- private LinearLayout mInCallControls;
-
- private static DialerActivity instance;
- public boolean mVisible;
- private boolean mPreventDoubleCallOnRotation;
-
- private AlertDialog wizardDialog;
- protected String username;
- private String key;
-
- private CameraView mVideoCaptureView;
- private int mCurrentCameraId = 0;
-
- private Camera mCamera;
-
-
- private static final String CURRENT_ADDRESS = "org.linphone.current-address";
- private static final String CURRENT_DISPLAYNAME = "org.linphone.current-displayname";
- private static final String PREVENT_DOUBLE_CALL = "prevent_call_on_phone_rotation";
-
- private static final int CONFIRM_ID = 0x668;
-
- /**
- * @return null if not ready yet
- */
- public static DialerActivity instance() {
- return instance;
- }
-
- private String getStatusIcon(RegistrationState state) {
- if (state == RegistrationState.RegistrationOk)
- return Integer.toString(R.drawable.status_green);
-
- else if (state == RegistrationState.RegistrationNone)
- return Integer.toString(R.drawable.status_red);
-
- else if (state == RegistrationState.RegistrationProgress)
- return Integer.toString(R.drawable.status_orange);
-
- else
- return Integer.toString(R.drawable.status_offline);
- }
-
- private void displayRegisterStatus() {
- ListView accounts = (ListView) findViewById(R.id.accounts);
- if (accounts != null) {
- accounts.setDividerHeight(0);
- ArrayList> hashMapAccountsStateList = new ArrayList>();
- for (LinphoneProxyConfig lpc : LinphoneManager.getLc().getProxyConfigList()) {
- HashMap entitiesHashMap = new HashMap();
- entitiesHashMap.put("Identity", lpc.getIdentity().split("sip:")[1]);
- entitiesHashMap.put("State", getStatusIcon(lpc.getState()));
- hashMapAccountsStateList.add(entitiesHashMap);
- }
- Adapter adapterForList = new SimpleAdapter(this, hashMapAccountsStateList, R.layout.accounts,
- new String[] {"Identity", "State"},
- new int[] { R.id.Identity, R.id.State });
- accounts.setAdapter((ListAdapter) adapterForList);
- accounts.invalidate();
- }
- }
-
- protected Dialog onCreateDialog (int id) {
- if (id == CONFIRM_ID) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.wizard_confirmation);
-
- final LayoutInflater inflater = LayoutInflater.from(this);
- View v = inflater.inflate(R.layout.wizard_confirm, null);
- builder.setView(v);
-
- Button check = (Button) v.findViewById(R.id.wizardCheckAccount);
- check.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- wizardDialog.dismiss();
- if (LinphonePreferencesActivity.isAccountVerified(username)) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(DialerActivity.this);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(getString(R.string.pref_activated_key) + key, true);
- editor.commit();
- } else {
- showDialog(CONFIRM_ID);
- }
- }
- });
-
- Button cancel = (Button) v.findViewById(R.id.wizardCancel);
- cancel.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- wizardDialog.dismiss();
- }
- });
-
- wizardDialog = builder.create();
- return wizardDialog;
- }
- return null;
- }
-
- private void verifiyAccountsActivated() {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- int nbAccounts = prefs.getInt(getString(R.string.pref_extra_accounts), 0);
-
- for (int i = 0; i < nbAccounts; i++) {
- String key = (i == 0 ? "" : Integer.toString(i));
- boolean createdByWizard = prefs.getBoolean(getString(R.string.pref_wizard_key) + key, false);
- boolean activated = prefs.getBoolean(getString(R.string.pref_activated_key) + key, true);
- if (createdByWizard && !activated) {
- //Check if account has been activated since
- String username = prefs.getString(getString(R.string.pref_username_key) + key, "");
- activated = LinphonePreferencesActivity.isAccountVerified(username);
- if (activated) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(getString(R.string.pref_activated_key) + key, true);
- editor.commit();
- } else {
- this.username = username;
- this.key = key;
- showDialog(CONFIRM_ID);
- }
- }
- }
- }
-
- public void onCreate(Bundle savedInstanceState) {
- if (Version.isXLargeScreen(this)) {
- this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- }
- setContentView(R.layout.dialer);
-
- mAddress = (AddressText) findViewById(R.id.SipUri);
- EraseButton erase = (EraseButton) findViewById(R.id.Erase);
- erase.setAddressWidget(mAddress);
- erase.requestFocus();
-
- mCall = (CallButton) findViewById(R.id.Call);
- mCall.setAddressWidget(mAddress);
- mBack = (Button) findViewById(R.id.Back);
- mAddCall = (Button) findViewById(R.id.AddCall);
- mInCallControls = (LinearLayout) findViewById(R.id.InCallControls);
- mStatus = (TextView) findViewById(R.id.status_label);
-
- if (mBack != null) {
- mBack.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
- if (call != null && call.getCurrentParamsCopy().getVideoEnabled())
- LinphoneActivity.instance().startVideoActivity(call, 0);
- else
- LinphoneActivity.instance().startIncallActivity();
- }
- });
- }
-
- if (mAddCall != null) {
- mAddCall.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
- if (call != null && !call.isInConference()) {
- LinphoneManager.getLc().pauseCall(call);
- } else {
- LinphoneManager.getLc().leaveConference();
- }
-
- try {
- LinphoneManager.getLc().invite(mAddress.getText().toString());
- } catch (LinphoneCoreException e) {
- Log.e(e);
- Toast.makeText(DialerActivity.this, R.string.error_adding_new_call, Toast.LENGTH_LONG).show();
- }
- }
- });
- }
-
- if (Version.isXLargeScreen(this)) {
- tryToInitTabletUI();
- }
-
- SlidingDrawer drawer = (SlidingDrawer) findViewById(R.id.drawer);
- if (drawer != null) {
- boolean disable_sliding_drawer = getResources().getBoolean(R.bool.disable_dialer_sliding_drawer);
-
- if (disable_sliding_drawer) {
- drawer.close();
- drawer.lock();
- } else {
- drawer.setOnDrawerScrollListener(new OnDrawerScrollListener() {
- public void onScrollEnded() {
-
- }
-
- public void onScrollStarted() {
- displayRegisterStatus();
- }
- });
- }
- }
-
- AddressAware numpad = (AddressAware) findViewById(R.id.Dialer);
- if (numpad != null)
- numpad.setAddressWidget(mAddress);
-
- // call to super must be done after all fields are initialized
- // because it may call this.enterIncallMode
- super.onCreate(savedInstanceState);
-
- mPreventDoubleCallOnRotation=savedInstanceState != null
- && savedInstanceState.getBoolean(PREVENT_DOUBLE_CALL, false);
- if (mPreventDoubleCallOnRotation) {
- Log.i("Prevent launching a new call on rotation");
- } else {
- checkIfOutgoingCallIntentReceived();
- }
-
- instance = this;
- super.onCreate(savedInstanceState);
-
- verifiyAccountsActivated();
-
- displayRegisterStatus();
- mCall.requestFocus();
- }
-
-
- private synchronized void tryToInitTabletUI() {
- final int numberOfCameras = Camera.getNumberOfCameras();
-
- CameraInfo cameraInfo = new CameraInfo();
- for (int i = 0; i < numberOfCameras; i++) {
- Camera.getCameraInfo(i, cameraInfo);
- if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
- mCurrentCameraId = i;
- }
- }
-
- mVideoCaptureView = (CameraView) findViewById(R.id.video_background);
- if (mVideoCaptureView != null)
- {
- if (mCamera == null) {
- mCamera = Camera.open(mCurrentCameraId);
- }
- mVideoCaptureView.setCamera(mCamera, mCurrentCameraId);
- mCamera.startPreview();
- }
-
- mSwitchCamera = (Button) findViewById(R.id.switch_camera);
- if (mSwitchCamera != null)
- {
- if (AndroidCameraConfiguration.hasSeveralCameras())
- mSwitchCamera.setVisibility(View.VISIBLE);
-
- mSwitchCamera.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- mCurrentCameraId = (mCurrentCameraId + 1) % numberOfCameras;
- mCamera.release();
- mVideoCaptureView.setCamera(null, -1);
-
- mCamera = Camera.open(mCurrentCameraId);
- mVideoCaptureView.switchCamera(mCamera, mCurrentCameraId);
- mCamera.startPreview();
- }
- });
- }
- }
-
- private void checkIfOutgoingCallIntentReceived() {
- if (getIntent().getData() == null) return;
-
- if (!LinphoneService.isReady() || LinphoneManager.getLc().isIncall()) {
- Log.w("Outgoing call aborted as LinphoneService"
- + " is not ready or we are already in call");
- return;
- }
-
- // Fix call from contact issue
- if (getIntent().getData().getSchemeSpecificPart() != null)
- getIntent().setAction(Intent.ACTION_CALL);
-
- newOutgoingCall(getIntent());
- }
-
-
-
- @Override
- protected void onPause() {
- super.onPause();
- mVisible = false;
-
- if (mCamera != null) {
- mCamera.release();
- mVideoCaptureView.setCamera(null, -1);
- mCamera = null;
- }
- }
-
-
-
-
-
-
-
- @Override
- public void onSaveInstanceState(Bundle savedInstanceState) {
- super.onSaveInstanceState(savedInstanceState);
- savedInstanceState.putCharSequence(CURRENT_ADDRESS, mAddress.getText());
- if (mAddress.getDisplayedName() != null)
- savedInstanceState.putString(CURRENT_DISPLAYNAME,mAddress.getDisplayedName());
- savedInstanceState.putBoolean(PREVENT_DOUBLE_CALL, mPreventDoubleCallOnRotation);
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedState) {
- super.onRestoreInstanceState(savedState);
- CharSequence addr = savedState.getCharSequence(CURRENT_ADDRESS);
- if (addr != null && mAddress != null) {
- mAddress.setText(addr);
- }
- mAddress.setDisplayedName(savedState.getString(CURRENT_DISPLAYNAME));
- }
-
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- instance=null;
- }
-
-
-
-
-
- public void newOutgoingCall(Intent intent) {
- String scheme = intent.getData().getScheme();
- if (scheme.startsWith("imto")) {
- mAddress.setText("sip:" + intent.getData().getLastPathSegment());
- } else if (scheme.startsWith("call") || scheme.startsWith("sip")) {
- mAddress.setText(intent.getData().getSchemeSpecificPart());
- } else {
- Log.e("Unknown scheme: ",scheme);
- mAddress.setText(intent.getData().getSchemeSpecificPart());
- }
-
- mAddress.clearDisplayedName();
- intent.setData(null);
- // Setting data to null is no use when the activity is recreated
- // as the intent is immutable.
- // https://groups.google.com/forum/#!topic/android-developers/vrLdM5mKeoY
- mPreventDoubleCallOnRotation=true;
- setIntent(intent);
-
- LinphoneManager.getInstance().newOutgoingCall(mAddress);
- }
-
-
- public void setContactAddress(String aContact,String aDisplayName, Uri photo) {
- mAddress.setText(aContact);
- mAddress.setDisplayedName(aDisplayName);
- mAddress.setPictureUri(photo);
- }
-
-
-
-
-
-
- /***** GUI delegates for listener LinphoneServiceListener *************/
- @Override
- public void onDisplayStatus(String message) {
- mStatus.setText(message);
- }
-
- @Override
- public void onAlreadyInCall() {
- showToast(R.string.warning_already_incall);
- }
-
- @Override
- public void onCannotGetCallParameters() {
- showToast(R.string.error_cannot_get_call_parameters,mAddress.getText());
- }
-
- @Override
- public void onWrongDestinationAddress() {
- showToast(R.string.warning_wrong_destination_address, mAddress.getText());
- }
-
- private void showToast(int id, String txt) {
- final String msg = String.format(getString(id), txt);
- Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
- }
- private void showToast(int id, CharSequence txt) {
- showToast(id, txt.toString());
- }
- private void showToast(int id) {
- Toast.makeText(this, getString(id), Toast.LENGTH_LONG).show();
- }
-
- @Override
- public void onCallStateChanged(LinphoneCall call, State s, String m) {
- if (mVideoCaptureView != null && mCamera == null && !LinphoneManager.getLc().isIncall())
- {
- if (mInCallControls != null)
- mInCallControls.setVisibility(View.GONE);
- mCall.setVisibility(View.VISIBLE);
-
- if (AndroidCameraConfiguration.hasSeveralCameras() && mSwitchCamera != null)
- mSwitchCamera.setVisibility(View.VISIBLE);
-
- mCamera = Camera.open(mCurrentCameraId);
- mVideoCaptureView.switchCamera(mCamera, mCurrentCameraId);
- mCamera.startPreview();
- }
- }
-
- public void onGlobalStateChangedToOn(String message) {
- mCall.setEnabled(!LinphoneManager.getLc().isIncall());
-
- if (getIntent().getData() != null) {
- checkIfOutgoingCallIntentReceived();
- }
- }
-
- @Override
- protected void onResume() {
- // When coming back from a video call, if the phone orientation is different
- // Android will destroy the previous Dialer and create a new one.
- // Unfortunately the "call end" status event is received in the meanwhile
- // and set to the to be destroyed Dialer.
- // Note1: We wait as long as possible before setting the last message.
- // Note2: Linphone service is in charge of instantiating LinphoneManager
- mVisible = true;
- mStatus.setText(LinphoneManager.getInstance().getLastLcStatusMessage());
-
- super.onResume();
-
- if (mInCallControls != null)
- mInCallControls.setVisibility(View.GONE);
- mCall.setVisibility(View.VISIBLE);
-
- if (AndroidCameraConfiguration.hasSeveralCameras() && mSwitchCamera != null)
- mSwitchCamera.setVisibility(View.VISIBLE);
-
- boolean callEstablished = isCallEstablished();
- boolean isInCall = LinphoneManager.getLc().getCallsNb() > 1 || (LinphoneManager.getLc().getCallsNb() == 1 && callEstablished);
-
- if (mVideoCaptureView != null && mCamera == null && !LinphoneManager.getLc().isIncall()) {
- mCamera = Camera.open(mCurrentCameraId);
- mVideoCaptureView.switchCamera(mCamera, mCurrentCameraId);
- mCamera.startPreview();
- } else if (isInCall) {
- if (mInCallControls != null) {
- mInCallControls.setVisibility(View.VISIBLE);
- mCall.setVisibility(View.GONE);
- }
-
- if (mSwitchCamera != null)
- mSwitchCamera.setVisibility(View.INVISIBLE);
- }
- }
-
- private boolean isCallEstablished()
- {
- if (LinphoneManager.getLc().getCalls().length == 0)
- return false;
-
- LinphoneCall call = LinphoneManager.getLc().getCalls()[0];
- LinphoneCall.State state = call.getState();
-
- return state == LinphoneCall.State.Connected ||
- state == LinphoneCall.State.CallUpdated ||
- state == LinphoneCall.State.CallUpdatedByRemote ||
- state == LinphoneCall.State.Paused ||
- state == LinphoneCall.State.PausedByRemote ||
- state == LinphoneCall.State.StreamsRunning ||
- state == LinphoneCall.State.Pausing ||
- state == LinphoneCall.State.Resuming;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (LinphoneUtils.onKeyVolumeAdjust(keyCode)) return true;
- boolean isInCall = LinphoneManager.getLc().isIncall();
- isInCall = isInCall || LinphoneManager.getLc().getCallsNb() > 0;
- if (keyCode == KeyEvent.KEYCODE_BACK && isInCall) {
- // If we are in call on dialer, we go back to the incall view
- LinphoneActivity.instance().startIncallActivity();
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-}
diff --git a/src/org/linphone/DialerFragment.java b/src/org/linphone/DialerFragment.java
new file mode 100644
index 000000000..89c6abcc1
--- /dev/null
+++ b/src/org/linphone/DialerFragment.java
@@ -0,0 +1,131 @@
+package org.linphone;
+/*
+DialerFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.ui.AddressAware;
+import org.linphone.ui.AddressText;
+import org.linphone.ui.CallButton;
+import org.linphone.ui.EraseButton;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class DialerFragment extends Fragment {
+ private static DialerFragment instance;
+ public boolean mVisible;
+ private AddressText mAddress;
+ private CallButton mCall;
+ private ImageView mAddContact;
+ private OnClickListener addContactListener, cancelListener;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ instance = this;
+ View view = inflater.inflate(R.layout.dialer, container, false);
+
+ mAddress = (AddressText) view.findViewById(R.id.Adress);
+ EraseButton erase = (EraseButton) view.findViewById(R.id.Erase);
+ erase.setAddressWidget(mAddress);
+ erase.requestFocus();
+
+ mCall = (CallButton) view.findViewById(R.id.Call);
+ mCall.setAddressWidget(mAddress);
+ if (LinphoneActivity.isInstanciated() && LinphoneActivity.instance().isInCallLayout()) {
+ mCall.setImageResource(R.drawable.plus);
+ } else {
+ mCall.setImageResource(R.drawable.call);
+ }
+
+ AddressAware numpad = (AddressAware) view.findViewById(R.id.Dialer);
+ if (numpad != null)
+ numpad.setAddressWidget(mAddress);
+
+ mAddContact = (ImageView) view.findViewById(R.id.addContact);
+ addContactListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = ContactHelper.prepareAddContactIntent(mAddress);
+ startActivity(intent);
+ }
+ };
+ cancelListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LinphoneActivity.instance().resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
+ }
+ };
+ mAddContact.setOnClickListener(addContactListener);
+
+ mAddContact.setEnabled(!(LinphoneActivity.isInstanciated() && LinphoneActivity.instance().isInCallLayout()));
+
+ if (getArguments() != null) {
+ String number = getArguments().getString("SipUri");
+ String displayName = getArguments().getString("DisplayName");
+ String photo = getArguments().getString("PhotoUri");
+ mAddress.setText(number);
+ if (displayName != null) {
+ mAddress.setDisplayedName(displayName);
+ }
+ if (photo != null) {
+ mAddress.setPictureUri(Uri.parse(photo));
+ }
+ }
+
+ return view;
+ }
+
+ /**
+ * @return null if not ready yet
+ */
+ public static DialerFragment instance() {
+ return instance;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().selectMenu(FragmentsAvailable.DIALER);
+ LinphoneActivity.instance().updateDialerFragment(this);
+ }
+ }
+
+ public void resetLayout() {
+ if (LinphoneActivity.instance().isInCallLayout()) {
+ mCall.setImageResource(R.drawable.plus);
+ mAddress.setText("");
+ mAddContact.setImageResource(R.drawable.cancel);
+ mAddContact.setOnClickListener(cancelListener);
+ } else {
+ mCall.setImageResource(R.drawable.call);
+ mAddContact.setImageResource(R.drawable.add_contact);
+ mAddContact.setOnClickListener(addContactListener);
+ }
+ }
+}
diff --git a/src/org/linphone/FirstLoginActivity.java b/src/org/linphone/FirstLoginActivity.java
deleted file mode 100644
index 67c2c5c2e..000000000
--- a/src/org/linphone/FirstLoginActivity.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
-IncallActivity.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.Log;
-import org.linphone.core.LinphoneCore.RegistrationState;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-public class FirstLoginActivity extends Activity implements OnClickListener {
-
- private TextView login;
- private TextView password;
- private SharedPreferences mPref;
- private ProgressBar bar;
- static FirstLoginActivity instance;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.first_login_view);
- mPref = PreferenceManager.getDefaultSharedPreferences(this);
- setDefaultDomain(getString(R.string.default_domain));
-
- login = (TextView) findViewById(R.id.login);
- login.setText(mPref.getString(getString(R.string.pref_username_key), ""));
-
- password = (TextView) findViewById(R.id.password);
- password.setText(mPref.getString(getString(R.string.pref_passwd_key), ""));
-
- bar = (ProgressBar) findViewById(R.id.progress_bar);
- bar.setVisibility(View.INVISIBLE);
-
-
- findViewById(R.id.connect).setOnClickListener(this);
- instance = this;
- }
-
- private void setDefaultDomain(String string) {
- String domain = mPref.getString(getString(R.string.pref_domain_key), "");
- if (domain.length() != 0) return;
-
- writePreference(R.string.pref_domain_key, getString(R.string.default_domain));
- }
-
- public void onClick(View v) {
- if (login.getText() == null || login.length() == 0
- || password.getText() == null || password.length() == 0) {
- toast(R.string.first_launch_no_login_password);
- return;
- }
-
- InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
-
- writePreference(R.string.pref_username_key, login.getText().toString());
- writePreference(R.string.pref_passwd_key, password.getText().toString());
-
- LinphoneManager.getInstance().initializePayloads();
-
- try {
- LinphoneManager.getInstance().initFromConf();
- } catch (Throwable e) {
- Log.e(e, "Error while initializing from config in first login activity");
- toast(R.string.error);;
- }
- }
-
-
-
- private void writePreference(int key, String value) {
- mPref.edit().putString(getString(key), value).commit();
- }
-
- @Override
- protected void onDestroy() {
- instance = null;
- super.onDestroy();
- }
-
- public void onRegistrationStateChanged(RegistrationState state) {
- if (RegistrationState.RegistrationOk == state) {
- bar.setVisibility(View.INVISIBLE);
- toast(R.string.first_launch_ok);
- mPref.edit().putBoolean(getString(R.string.first_launch_suceeded_once_key), true).commit();
- setResult(RESULT_OK);
- finish();
- } else if (RegistrationState.RegistrationFailed == state) {
- bar.setVisibility(View.INVISIBLE);
- toast(R.string.first_launch_bad_login_password);
- } else if (RegistrationState.RegistrationProgress == state) {
- bar.setVisibility(View.VISIBLE);
- }
- }
-
- private void toast(int key) {
- Toast.makeText(instance, instance.getString(key), Toast.LENGTH_LONG).show();
- }
-
-}
diff --git a/src/org/linphone/FragmentsAvailable.java b/src/org/linphone/FragmentsAvailable.java
new file mode 100644
index 000000000..c4d8c7035
--- /dev/null
+++ b/src/org/linphone/FragmentsAvailable.java
@@ -0,0 +1,72 @@
+package org.linphone;
+/*
+FragmentsAvailable.java
+Copyright (C) 2012 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.
+*/
+/**
+ * @author Sylvain Berfini
+ */
+public enum FragmentsAvailable {
+ UNKNOW,
+ DIALER,
+ HISTORY,
+ HISTORY_DETAIL,
+ CONTACTS,
+ CONTACT,
+ SETTINGS,
+ CHATLIST,
+ CHAT;
+
+ public boolean shouldAddToBackStack() {
+ return true;
+ }
+
+ public boolean shouldAnimate() {
+ return true;
+ }
+
+ public boolean isRightOf(FragmentsAvailable fragment) {
+ switch (this) {
+ case HISTORY:
+ return fragment == UNKNOW;
+
+ case HISTORY_DETAIL:
+ return HISTORY.isRightOf(fragment) || fragment == HISTORY;
+
+ case CONTACTS:
+ return HISTORY_DETAIL.isRightOf(fragment) || fragment == HISTORY_DETAIL;
+
+ case CONTACT:
+ return CONTACTS.isRightOf(fragment) || fragment == CONTACTS;
+
+ case DIALER:
+ return CONTACTS.isRightOf(fragment) || fragment == CONTACT || fragment == CONTACTS;
+
+ case SETTINGS:
+ return DIALER.isRightOf(fragment) || fragment == DIALER;
+
+ case CHATLIST:
+ return SETTINGS.isRightOf(fragment) || fragment == SETTINGS;
+
+ case CHAT:
+ return CHATLIST.isRightOf(fragment) || fragment == CHATLIST;
+
+ default:
+ return false;
+ }
+ }
+}
diff --git a/src/org/linphone/HistoryActivity.java b/src/org/linphone/HistoryActivity.java
deleted file mode 100644
index 8be51601e..000000000
--- a/src/org/linphone/HistoryActivity.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
-DialerActivity.java
-Copyright (C) 2010 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.Arrays;
-import java.util.List;
-
-import org.linphone.core.CallDirection;
-import org.linphone.core.LinphoneAddress;
-import org.linphone.core.LinphoneCallLog;
-import org.linphone.core.LinphoneCore;
-import org.linphone.core.LinphoneProxyConfig;
-import org.linphone.core.Log;
-
-import android.app.ListActivity;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class HistoryActivity extends ListActivity {
- LayoutInflater mInflater;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
-
-
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- super.onListItemClick(l, v, position, id);
- TextView lFirstLineView = (TextView) v.findViewById(R.id.history_cell_first_line);
- TextView lSecondLineView = (TextView) v.findViewById(R.id.history_cell_second_line);
- ContactPicked parent = (ContactPicked) getParent();
- if (lSecondLineView.getVisibility() == View.GONE) {
- // no display name
- parent.setAddressAndGoToDialer(lFirstLineView.getText().toString(), null, null);
- } else {
- parent.setAddressAndGoToDialer(
- lSecondLineView.getText().toString(),
- lFirstLineView.getText().toString(),
- null);
- }
- }
-
-
- @Override
- protected void onResume() {
- super.onResume();
- setListAdapter(new CallHistoryAdapter(this));
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the currently selected menu XML resource.
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.history_activity_menu, menu);
- return true;
- }
-
- // Fix the menu from crashing the activity
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
- if (id == R.id.menu_clear_history) {
- LinphoneManager.getLc().clearCallLogs();
- setListAdapter(new CallHistoryAdapter(this));
- }
- else {
- Log.e("Unknown menu item [",item,"]");
- }
-
- return false;
- }
-
- class CallHistoryAdapter extends BaseAdapter {
- final List mLogs;
-
- CallHistoryAdapter(Context aContext) {
- mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs());
- }
- public int getCount() {
- return mLogs.size();
- }
-
- public Object getItem(int position) {
- return position;
- }
-
- public long getItemId(int position) {
-
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View lView=null;
- if (convertView !=null) {
- lView = convertView;
- } else {
- lView = mInflater.inflate(R.layout.history_cell, parent,false);
-
- }
- LinphoneCallLog lLog = mLogs.get(position);
- LinphoneAddress lAddress;
- TextView lFirstLineView = (TextView) lView.findViewById(R.id.history_cell_first_line);
- TextView lSecondLineView = (TextView) lView.findViewById(R.id.history_cell_second_line);
- ImageView lDirectionImageIn = (ImageView) lView.findViewById(R.id.history_cell_icon_in);
- ImageView lDirectionImageOut = (ImageView) lView.findViewById(R.id.history_cell_icon_out);
- ImageView lContactPicture = (ImageView) lView.findViewById(R.id.history_cell_icon_contact);
-
- if (lLog.getDirection() == CallDirection.Incoming) {
- lAddress = lLog.getFrom();
- lDirectionImageIn.setVisibility(View.VISIBLE);
- lDirectionImageOut.setVisibility(View.GONE);
-
- } else {
- lAddress = lLog.getTo();
- lDirectionImageIn.setVisibility(View.GONE);
- lDirectionImageOut.setVisibility(View.VISIBLE);
- }
-
- Uri uri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, getContentResolver());
- LinphoneUtils.setImagePictureFromUri(lView.getContext(), lContactPicture, uri, R.drawable.unknown_person);
-
- LinphoneCore lc = LinphoneManager.getLc();
- LinphoneProxyConfig lProxyConfig = lc.getDefaultProxyConfig();
- boolean showOnlyUsername = getResources().getBoolean(R.bool.show_only_username_in_history);
- String lDetailedName=null;
- String lDisplayName = !showOnlyUsername ? lAddress.getDisplayName() : null;
- if (showOnlyUsername || (lProxyConfig != null && lProxyConfig.getDomain().equals(lAddress.getDomain()))) {
- lDetailedName = lAddress.getUserName();
- } else {
- lDetailedName = lAddress.asStringUriOnly();
- }
-
- if (lDisplayName == null) {
- lFirstLineView.setText(lDetailedName);
- lSecondLineView.setVisibility(View.GONE);
- } else {
- lFirstLineView.setText(lDisplayName);
- lSecondLineView.setText(lDetailedName);
- lSecondLineView.setVisibility(View.VISIBLE);
- }
-
- return lView;
-
- }
-
- }
-}
diff --git a/src/org/linphone/HistoryDetailFragment.java b/src/org/linphone/HistoryDetailFragment.java
new file mode 100644
index 000000000..87b221a14
--- /dev/null
+++ b/src/org/linphone/HistoryDetailFragment.java
@@ -0,0 +1,109 @@
+package org.linphone;
+/*
+HistoryDetailFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.compatibility.Compatibility;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class HistoryDetailFragment extends Fragment implements OnClickListener {
+ private ImageView contactPicture, dialBack, chat, addToContacts;
+ private TextView contactName, callDirection, time, date, dialBackUri;
+ private String sipUri, displayName, pictureUri;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ sipUri = getArguments().getString("SipUri");
+ displayName = getArguments().getString("DisplayName");
+ pictureUri = getArguments().getString("PictureUri");
+ String status = getArguments().getString("CallStatus");
+ String callTime = getArguments().getString("CallTime");
+ String callDate = getArguments().getString("CallDate");
+
+ View view = inflater.inflate(R.layout.history_detail, container, false);
+
+ contactPicture = (ImageView) view.findViewById(R.id.contactPicture);
+ if (pictureUri != null) {
+ LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture, Uri.parse(pictureUri), R.drawable.unknown_small);
+ }
+
+ dialBack = (ImageView) view.findViewById(R.id.dialBack);
+ dialBack.setOnClickListener(this);
+
+ chat = (ImageView) view.findViewById(R.id.chat);
+ chat.setOnClickListener(this);
+
+ addToContacts = (ImageView) view.findViewById(R.id.addToContacts);
+ addToContacts.setOnClickListener(this);
+
+ contactName = (TextView) view.findViewById(R.id.contactName);
+ if (displayName == null && getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(sipUri)) {
+ displayName = LinphoneUtils.getUsernameFromAddress(sipUri);
+ }
+ contactName.setText(displayName == null ? sipUri : displayName);
+
+ dialBackUri = (TextView) view.findViewById(R.id.dialBackUri);
+ dialBackUri.setText(sipUri);
+
+ callDirection = (TextView) view.findViewById(R.id.callDirection);
+ callDirection.setText(status);
+
+ time = (TextView) view.findViewById(R.id.time);
+ time.setText(callTime == null ? "" : callTime);
+ date = (TextView) view.findViewById(R.id.date);
+ date.setText(callDate == null ? "" : callDate);
+
+
+ return view;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().selectMenu(FragmentsAvailable.HISTORY_DETAIL);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (id == R.id.dialBack) {
+ LinphoneActivity.instance().setAddresGoToDialerAndCall(sipUri, displayName, pictureUri == null ? null : Uri.parse(pictureUri));
+ } else if (id == R.id.chat) {
+ LinphoneActivity.instance().displayChat(sipUri);
+ } else if (id == R.id.addToContacts) {
+ Intent intent = Compatibility.prepareAddContactIntent(displayName, sipUri);
+ startActivity(intent);
+ }
+ }
+}
diff --git a/src/org/linphone/HistoryFragment.java b/src/org/linphone/HistoryFragment.java
new file mode 100644
index 000000000..d2d38e999
--- /dev/null
+++ b/src/org/linphone/HistoryFragment.java
@@ -0,0 +1,228 @@
+package org.linphone;
+/*
+HistoryFragment.java
+Copyright (C) 2012 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.
+*/
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.linphone.core.CallDirection;
+import org.linphone.core.LinphoneAddress;
+import org.linphone.core.LinphoneCallLog;
+import org.linphone.core.LinphoneCallLog.CallStatus;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class HistoryFragment extends Fragment implements OnClickListener, OnItemClickListener {
+ private ListView historyList;
+ private LayoutInflater mInflater;
+ private ImageView allCalls, missedCalls, edit, ok;
+ private boolean onlyDisplayMissedCalls, isEditMode;
+ private List mLogs;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mInflater = inflater;
+ View view = inflater.inflate(R.layout.history, container, false);
+
+ historyList = (ListView) view.findViewById(R.id.historyList);
+ historyList.setOnItemClickListener(this);
+
+ allCalls = (ImageView) view.findViewById(R.id.allCalls);
+ allCalls.setOnClickListener(this);
+ missedCalls = (ImageView) view.findViewById(R.id.missedCalls);
+ missedCalls.setOnClickListener(this);
+ allCalls.setEnabled(false);
+ onlyDisplayMissedCalls = false;
+ edit = (ImageView) view.findViewById(R.id.edit);
+ edit.setOnClickListener(this);
+ ok = (ImageView) view.findViewById(R.id.ok);
+ ok.setOnClickListener(this);
+
+ return view;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (LinphoneActivity.isInstanciated())
+ LinphoneActivity.instance().selectMenu(FragmentsAvailable.HISTORY);
+
+ mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs());
+ historyList.setAdapter(new CallHistoryAdapter(getActivity().getApplicationContext()));
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (id == R.id.allCalls) {
+ allCalls.setEnabled(false);
+ missedCalls.setEnabled(true);
+ onlyDisplayMissedCalls = false;
+
+ mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs());
+ }
+ else if (id == R.id.missedCalls) {
+ allCalls.setEnabled(true);
+ missedCalls.setEnabled(false);
+ onlyDisplayMissedCalls = true;
+ }
+ else if (id == R.id.ok) {
+ edit.setVisibility(View.VISIBLE);
+ ok.setVisibility(View.GONE);
+ isEditMode = false;
+ }
+ else if (id == R.id.edit) {
+ edit.setVisibility(View.GONE);
+ ok.setVisibility(View.VISIBLE);
+ isEditMode = true;
+ }
+
+ historyList.setAdapter(new CallHistoryAdapter(getActivity().getApplicationContext()));
+ }
+
+ @Override
+ public void onItemClick(AdapterView> adapter, View view, int position, long id) {
+ if (isEditMode) {
+ LinphoneCallLog log = mLogs.get(position);
+ LinphoneManager.getLc().removeCallLog(log);
+ mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs());
+ historyList.setAdapter(new CallHistoryAdapter(getActivity().getApplicationContext()));
+ } else {
+ LinphoneCallLog log = mLogs.get(position);
+ LinphoneAddress address;
+ if (log.getDirection() == CallDirection.Incoming) {
+ address = log.getFrom();
+ } else {
+ address = log.getTo();
+ }
+ LinphoneActivity.instance().displayHistoryDetail(address.asStringUriOnly(), log);
+ }
+ }
+
+ class CallHistoryAdapter extends BaseAdapter {
+ private Bitmap missedCall, outgoingCall, incomingCall;
+
+ CallHistoryAdapter(Context aContext) {
+ missedCall = BitmapFactory.decodeResource(getResources(), R.drawable.call_status_missed);
+
+ if (onlyDisplayMissedCalls) {
+ List missedCalls = new ArrayList();
+ for (LinphoneCallLog log : mLogs) {
+ if (log.getStatus() == CallStatus.Missed) {
+ missedCalls.add(log);
+ }
+ }
+ mLogs = missedCalls;
+ } else {
+ outgoingCall = BitmapFactory.decodeResource(getResources(), R.drawable.call_status_outgoing);
+ incomingCall = BitmapFactory.decodeResource(getResources(), R.drawable.call_status_incoming);
+ }
+ }
+ public int getCount() {
+ return mLogs.size();
+ }
+
+ public Object getItem(int position) {
+ return mLogs.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = null;
+ if (convertView != null) {
+ view = convertView;
+ } else {
+ view = mInflater.inflate(R.layout.history_cell, parent,false);
+ }
+
+ LinphoneCallLog log = mLogs.get(position);
+ LinphoneAddress address;
+
+ TextView contact = (TextView) view.findViewById(R.id.sipUri);
+ ImageView detail = (ImageView) view.findViewById(R.id.detail);
+ ImageView delete = (ImageView) view.findViewById(R.id.delete);
+ ImageView callDirection = (ImageView) view.findViewById(R.id.icon);
+
+
+ if (log.getDirection() == CallDirection.Incoming) {
+ address = log.getFrom();
+ if (log.getStatus() == CallStatus.Missed) {
+ callDirection.setImageBitmap(missedCall);
+ } else {
+ callDirection.setImageBitmap(incomingCall);
+ }
+ } else {
+ address = log.getTo();
+ callDirection.setImageBitmap(outgoingCall);
+ }
+
+ LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, view.getContext().getContentResolver());
+ String displayName = address.getDisplayName();
+ String sipUri = address.asStringUriOnly();
+
+ if (displayName == null) {
+ if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(sipUri)) {
+ contact.setText(LinphoneUtils.getUsernameFromAddress(sipUri));
+ } else {
+ contact.setText(sipUri);
+ }
+ } else {
+ if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(address.getDisplayName())) {
+ contact.setText(LinphoneUtils.getUsernameFromAddress(address.getDisplayName()));
+ } else {
+ contact.setText(displayName);
+ }
+ }
+ view.setTag(sipUri);
+
+ if (isEditMode) {
+ delete.setVisibility(View.VISIBLE);
+ detail.setVisibility(View.GONE);
+ } else {
+ delete.setVisibility(View.GONE);
+ detail.setVisibility(View.VISIBLE);
+ }
+
+ return view;
+ }
+
+ }
+}
diff --git a/src/org/linphone/InCallActivity.java b/src/org/linphone/InCallActivity.java
new file mode 100644
index 000000000..f1a71e814
--- /dev/null
+++ b/src/org/linphone/InCallActivity.java
@@ -0,0 +1,487 @@
+package org.linphone;
+/*
+InCallActivity.java
+Copyright (C) 2012 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.
+*/
+import java.util.Arrays;
+import java.util.List;
+
+import org.linphone.LinphoneSimpleListener.LinphoneOnCallEncryptionChangedListener;
+import org.linphone.LinphoneSimpleListener.LinphoneOnCallStateChangedListener;
+import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCall.State;
+import org.linphone.core.LinphoneCallParams;
+import org.linphone.core.LinphoneCore;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+//FIXME : Chronometer for calls
+/**
+ * @author Sylvain Berfini
+ */
+public class InCallActivity extends FragmentActivity implements
+ LinphoneOnCallStateChangedListener,
+ LinphoneOnCallEncryptionChangedListener,
+ OnClickListener {
+ private final static int SECONDS_BEFORE_HIDING_CONTROLS = 3000;
+
+ private static InCallActivity instance;
+ private Handler mHandler = new Handler();
+ private Handler controlsHandler = new Handler();
+ private Runnable mControls;
+ private ImageView video, micro, speaker, addCall, pause, hangUp, dialer, switchCamera;
+ private StatusFragment status;
+ private AudioCallFragment audioCallFragment;
+ private VideoCallFragment videoCallFragment;
+ private boolean isSpeakerEnabled = false, isMicMuted = false, isVideoEnabled = false;
+ private LinearLayout mControlsLayout;
+
+ static final boolean isInstanciated() {
+ return instance != null;
+ }
+
+ public static final InCallActivity instance() {
+ return instance;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.incall);
+ instance = this;
+
+ if (findViewById(R.id.fragmentContainer) != null) {
+ if (savedInstanceState != null) {
+ return;
+ }
+ initUI();
+
+ if (LinphoneManager.getLc().getCallsNb() > 0) {
+ LinphoneCall call = LinphoneManager.getLc().getCalls()[0];
+
+ if (isCallEstablished(call)) {
+ enableAndRefreshInCallActions();
+ isVideoEnabled = call.getCurrentParamsCopy().getVideoEnabled();
+ }
+ }
+
+ Fragment callFragment;
+ if (isVideoEnabled) {
+ callFragment = new VideoCallFragment();
+ videoCallFragment = (VideoCallFragment) callFragment;
+ switchCamera.setVisibility(View.VISIBLE);
+ } else {
+ callFragment = new AudioCallFragment();
+ audioCallFragment = (AudioCallFragment) callFragment;
+ switchCamera.setVisibility(View.GONE);
+ }
+ callFragment.setArguments(getIntent().getExtras());
+ getSupportFragmentManager().beginTransaction().add(R.id.fragmentContainer, callFragment).commit();
+ }
+
+ LinphoneManager.addListener(this);
+ }
+
+ private void initUI() {
+ video = (ImageView) findViewById(R.id.video);
+ video.setOnClickListener(this);
+ video.setEnabled(false);
+ micro = (ImageView) findViewById(R.id.micro);
+ micro.setOnClickListener(this);
+ micro.setEnabled(false);
+ speaker = (ImageView) findViewById(R.id.speaker);
+ speaker.setOnClickListener(this);
+ speaker.setEnabled(false);
+ addCall = (ImageView) findViewById(R.id.addCall);
+ addCall.setOnClickListener(this);
+ addCall.setEnabled(false);
+ pause = (ImageView) findViewById(R.id.pause);
+ pause.setOnClickListener(this);
+ pause.setEnabled(false);
+ hangUp = (ImageView) findViewById(R.id.hangUp);
+ hangUp.setOnClickListener(this);
+ dialer = (ImageView) findViewById(R.id.dialer);
+ dialer.setOnClickListener(this);
+ dialer.setEnabled(false);
+
+ switchCamera = (ImageView) findViewById(R.id.switchCamera);
+ switchCamera.setOnClickListener(this);
+
+ mControlsLayout = (LinearLayout) findViewById(R.id.menu);
+ }
+
+ private void enableAndRefreshInCallActions() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ video.setEnabled(true);
+ micro.setEnabled(true);
+ speaker.setEnabled(true);
+ addCall.setEnabled(true);
+ pause.setEnabled(true);
+ dialer.setEnabled(true);
+
+ if (isVideoEnabled) {
+ video.setImageResource(R.drawable.video_on);
+ } else {
+ video.setImageResource(R.drawable.video_off);
+ }
+
+ if (isSpeakerEnabled) {
+ speaker.setImageResource(R.drawable.speaker_on);
+ } else {
+ speaker.setImageResource(R.drawable.speaker_off);
+ }
+
+ if (isMicMuted) {
+ micro.setImageResource(R.drawable.micro_off);
+ } else {
+ micro.setImageResource(R.drawable.micro_on);
+ }
+ }
+ });
+ }
+
+ public void updateStatusFragment(StatusFragment statusFragment) {
+ status = statusFragment;
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (isVideoEnabled) {
+ displayVideoCallControlsIfHidden();
+ }
+
+ if (id == R.id.video) {
+ isVideoEnabled = !isVideoEnabled;
+ switchVideo(isVideoEnabled);
+ }
+ else if (id == R.id.micro) {
+ toogleMicro();
+ }
+ else if (id == R.id.speaker) {
+ toogleSpeaker();
+ }
+ else if (id == R.id.addCall) {
+ setResult(Activity.RESULT_FIRST_USER);
+ finish();
+ }
+ else if (id == R.id.pause) {
+ pause();
+ }
+ else if (id == R.id.hangUp) {
+ hangUp();
+ }
+ else if (id == R.id.dialer) {
+
+ }
+ else if (id == R.id.switchCamera) {
+ if (videoCallFragment != null) {
+ videoCallFragment.switchCamera();
+ }
+ }
+ }
+
+
+ private void switchVideo(final boolean displayVideo) {
+ final LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
+ if (call == null) {
+ return;
+ }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (!displayVideo) {
+ LinphoneCallParams params = call.getCurrentParamsCopy();
+ params.setVideoEnabled(false);
+ LinphoneManager.getLc().updateCall(call, params);
+ replaceFragmentVideoByAudio();
+
+ isSpeakerEnabled = false;
+ LinphoneManager.getInstance().routeAudioToReceiver();
+ speaker.setImageResource(R.drawable.speaker_off);
+
+ video.setImageResource(R.drawable.video_on);
+ setCallControlsVisibleAndRemoveCallbacks();
+
+ } else {
+ if (!call.getCurrentParamsCopy().getVideoEnabled()) {
+ LinphoneManager.getInstance().addVideo();
+ }
+
+ isSpeakerEnabled = true;
+ LinphoneManager.getInstance().routeAudioToSpeaker();
+ speaker.setImageResource(R.drawable.speaker_on);
+
+ replaceFragmentAudioByVideo();
+ video.setImageResource(R.drawable.video_off);
+ displayVideoCallControlsIfHidden();
+ }
+ LinphoneManager.getLc().enableSpeaker(true);
+ }
+ });
+ }
+
+ private void replaceFragmentVideoByAudio() {
+ audioCallFragment = new AudioCallFragment();
+
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fragmentContainer, audioCallFragment);
+ try {
+ transaction.commitAllowingStateLoss();
+ } catch (Exception e) {
+ }
+ }
+
+ private void replaceFragmentAudioByVideo() {
+ switchCamera.setVisibility(View.VISIBLE);
+ videoCallFragment = new VideoCallFragment();
+
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fragmentContainer, videoCallFragment);
+ try {
+ transaction.commitAllowingStateLoss();
+ } catch (Exception e) {
+ }
+ }
+
+ private void toogleMicro() {
+ LinphoneCore lc = LinphoneManager.getLc();
+ isMicMuted = !isMicMuted;
+ lc.muteMic(isMicMuted);
+ if (isMicMuted) {
+ micro.setImageResource(R.drawable.micro_off);
+ } else {
+ micro.setImageResource(R.drawable.micro_on);
+ }
+ }
+
+ private void toogleSpeaker() {
+ isSpeakerEnabled = !isSpeakerEnabled;
+ if (isSpeakerEnabled) {
+ LinphoneManager.getInstance().routeAudioToSpeaker();
+ speaker.setImageResource(R.drawable.speaker_on);
+ } else {
+ LinphoneManager.getInstance().routeAudioToReceiver();
+ speaker.setImageResource(R.drawable.speaker_off);
+ }
+ LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
+ }
+
+ private void pause() {
+ LinphoneCore lc = LinphoneManager.getLc();
+ LinphoneCall call = lc.getCurrentCall();
+ if (call != null && isCallRunning(call)) {
+ lc.pauseCall(call);
+ pause.setImageResource(R.drawable.pause_on);
+ } else {
+ List pausedCalls = LinphoneUtils.getCallsInState(lc, Arrays.asList(State.Paused));
+ if (pausedCalls.size() == 1) {
+ LinphoneCall callToResume = pausedCalls.get(0);
+ lc.resumeCall(callToResume);
+ pause.setImageResource(R.drawable.pause_off);
+ }
+ }
+ }
+
+ private void hangUp() {
+ LinphoneCore lc = LinphoneManager.getLc();
+ LinphoneCall currentCall = lc.getCurrentCall();
+
+ if (currentCall != null) {
+ lc.terminateCall(currentCall);
+ } else if (lc.isInConference()) {
+ lc.terminateConference();
+ } else {
+ lc.terminateAllCalls();
+ }
+ }
+
+ public void displayVideoCallControlsIfHidden() {
+ if (mControlsLayout != null) {
+ if (mControlsLayout.getVisibility() == View.GONE) {
+ if (InCallActivity.this.getResources().getBoolean(R.bool.disable_animations)) {
+ mControlsLayout.setVisibility(View.VISIBLE);
+ switchCamera.setVisibility(View.VISIBLE);
+ } else {
+ Animation animation = AnimationUtils.loadAnimation(this, R.anim.slide_in_bottom_to_top);
+ animation.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ mControlsLayout.setVisibility(View.VISIBLE);
+ switchCamera.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ }
+ });
+ mControlsLayout.startAnimation(animation);
+ switchCamera.startAnimation(AnimationUtils.loadAnimation(this, R.anim.slide_in_top_to_bottom));
+ }
+ }
+
+ if (mControls != null) {
+ controlsHandler.removeCallbacks(mControls);
+ }
+
+ controlsHandler.postDelayed(mControls = new Runnable() {
+ public void run() {
+ if (InCallActivity.this.getResources().getBoolean(R.bool.disable_animations)) {
+ mControlsLayout.setVisibility(View.GONE);
+ switchCamera.setVisibility(View.GONE);
+ } else {
+ Animation animation = AnimationUtils.loadAnimation(InCallActivity.this, R.anim.slide_out_top_to_bottom);
+ animation.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ mControlsLayout.setVisibility(View.GONE);
+ switchCamera.setVisibility(View.GONE);
+ }
+ });
+ mControlsLayout.startAnimation(animation);
+ switchCamera.startAnimation(AnimationUtils.loadAnimation(InCallActivity.this, R.anim.slide_out_bottom_to_top));
+ }
+ }
+ }, SECONDS_BEFORE_HIDING_CONTROLS);
+ }
+ }
+
+ public void setCallControlsVisibleAndRemoveCallbacks() {
+ if (controlsHandler != null && mControls != null) {
+ controlsHandler.removeCallbacks(mControls);
+ mControls = null;
+ }
+
+ mControlsLayout.setVisibility(View.VISIBLE);
+ switchCamera.setVisibility(View.GONE);
+ }
+
+ private boolean isCallRunning(LinphoneCall call)
+ {
+ LinphoneCall.State state = call.getState();
+
+ return state == LinphoneCall.State.Connected ||
+ state == LinphoneCall.State.CallUpdated ||
+ state == LinphoneCall.State.CallUpdatedByRemote ||
+ state == LinphoneCall.State.StreamsRunning ||
+ state == LinphoneCall.State.Resuming;
+ }
+
+ private boolean isCallEstablished(LinphoneCall call) {
+ LinphoneCall.State state = call.getState();
+
+ return isCallRunning(call) ||
+ state == LinphoneCall.State.Paused ||
+ state == LinphoneCall.State.PausedByRemote ||
+ state == LinphoneCall.State.Pausing;
+ }
+
+ @Override
+ public void onCallStateChanged(LinphoneCall call, State state,
+ String message) {
+ if (LinphoneManager.getLc().getCallsNb() == 0) {
+ finish();
+ return;
+ }
+
+ if (state == State.StreamsRunning) {
+ boolean isVideoEnabledInCall = call.getCurrentParamsCopy().getVideoEnabled();
+ if (isVideoEnabledInCall != isVideoEnabled) {
+ isVideoEnabled = isVideoEnabledInCall;
+ switchVideo(isVideoEnabled);
+ }
+
+ isMicMuted = LinphoneManager.getLc().isMicMuted();
+ enableAndRefreshInCallActions();
+ }
+
+ if (audioCallFragment != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ audioCallFragment.refreshCallList(getResources());
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onCallEncryptionChanged(LinphoneCall call, boolean encrypted,
+ String authenticationToken) {
+ if (status != null) {
+ status.refreshEncryptionIcon();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (isVideoEnabled) {
+ displayVideoCallControlsIfHidden();
+ } else {
+ setCallControlsVisibleAndRemoveCallbacks();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ setCallControlsVisibleAndRemoveCallbacks();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (LinphoneUtils.onKeyVolumeAdjust(keyCode)) return true;
+ if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) return true;
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public void bindAudioFragment(AudioCallFragment fragment) {
+ audioCallFragment = fragment;
+ }
+}
diff --git a/src/org/linphone/IncallActivity.java b/src/org/linphone/IncallActivity.java
deleted file mode 100644
index 4cea2330f..000000000
--- a/src/org/linphone/IncallActivity.java
+++ /dev/null
@@ -1,857 +0,0 @@
-/*
-IncallActivity.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 static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.List;
-
-import org.linphone.LinphoneSimpleListener.LinphoneOnAudioChangedListener;
-import org.linphone.LinphoneSimpleListener.LinphoneOnCallEncryptionChangedListener;
-import org.linphone.LinphoneSimpleListener.LinphoneOnCallStateChangedListener;
-import org.linphone.core.LinphoneAddress;
-import org.linphone.core.LinphoneCall;
-import org.linphone.core.LinphoneCall.State;
-import org.linphone.core.LinphoneCallParams;
-import org.linphone.core.LinphoneCore.MediaEncryption;
-import org.linphone.core.LinphoneCoreException;
-import org.linphone.core.Log;
-import org.linphone.mediastream.Version;
-import org.linphone.ui.Numpad;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.os.CountDownTimer;
-import android.os.Handler;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.Checkable;
-import android.widget.ImageView;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-import android.widget.Toast;
-
-/**
- * @author Guillaume Beraudo
- */
-public class IncallActivity extends AbstractCalleesActivity implements
- LinphoneOnAudioChangedListener,
- LinphoneOnCallStateChangedListener,
- LinphoneOnCallEncryptionChangedListener,
- Comparator,
- OnLongClickListener,
- OnClickListener {
-
- private boolean mUnMuteOnReturnFromUriPicker;
-
- private static final int numpadDialogId = 1;
- private static final int addCallId = 1;
- private static final int transferCallId = 2;
- private static final int promptVideoId = 3;
-
- private static IncallActivity instance;
- private CountDownTimer timer;
- public static boolean active;
- @Override protected synchronized void setActive(boolean a) {active = a;}
- @Override protected synchronized boolean isActive() {return active;}
-
- public static boolean isReady() {
- return instance!=null;
- }
-
- static IncallActivity instance() {
- if (isReady()) return instance;
- return null;
- }
-
- private void pauseCurrentCallOrLeaveConference() {
- LinphoneCall call = lc().getCurrentCall();
- if (call != null && !call.isInConference()) {
- lc().pauseCall(call);
- } else {
- lc().leaveConference();
- updateConfItem();
- }
- }
-
- private View mConferenceVirtualCallee;
- private int mMultipleCallsLimit;
- private boolean mAllowTransfers;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setActive(true);
-
- if (finishIfAutoRestartAfterACrash(savedInstanceState)) {
- setActive(false);
- return;
- }
-
- if (!Version.isXLargeScreen(this))
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-
- setContentView(R.layout.incall_layout);
- instance = this;
-
- mAllowTransfers = getResources().getBoolean(R.bool.allow_transfers);
-
- findViewById(R.id.addCall).setOnClickListener(this);
-
- findViewById(R.id.incallNumpadShow).setOnClickListener(this);
- findViewById(R.id.conf_simple_merge).setOnClickListener(this);
- findViewById(R.id.conf_simple_pause).setOnClickListener(this);
-
- findViewById(R.id.incallHang).setOnClickListener(this);
- mMultipleCallsLimit = lc().getMaxCalls();
-
- mConferenceVirtualCallee = findViewById(R.id.conf_header);
- mConferenceVirtualCallee.setOnClickListener(this);
- mConferenceVirtualCallee.setOnLongClickListener(this);
- enableView(mConferenceVirtualCallee, R.id.conf_header_details, this, true);
-
-
- boolean mMayDoVideo = Version.isVideoCapable() && LinphoneManager.getInstance().isVideoEnabled();
- if (mMayDoVideo) {
- findViewById(R.id.conf_simple_video).setOnClickListener(this);
- } else {
- findViewById(R.id.conf_simple_video).setVisibility(View.GONE);
- }
- super.onCreate(savedInstanceState);
- }
-
- @Override
- protected void onPause() {
- setActive(false);
- instance = null;
- super.onPause();
- }
-
- @Override
- protected boolean shouldFinishCalleeActivity() {
- return lc().getCallsNb() == 0;
- }
-
- @Override
- protected CalleeListAdapter createCalleeListAdapter() {
- return new IncallListAdapter();
- }
-
-
-
- @Override
- protected List updateSpecificCallsList() {
- return LinphoneUtils.getLinphoneCallsNotInConf(lc());
- }
-
-
-
- private void updateSoundLock() {
- boolean locked = lc().soundResourcesLocked();
- findViewById(R.id.addCall).setEnabled(!locked);
- }
-
- private void updateAddCallButton() {
- boolean limitReached = false;
- if (mMultipleCallsLimit > 0) {
- limitReached = lc().getCallsNb() >= mMultipleCallsLimit;
- }
- findViewById(R.id.addCall).setVisibility(limitReached? View.INVISIBLE : VISIBLE);
- }
-
- private void updateNumpadButton() {
- LinphoneCall currentCall = lc().getCurrentCall();
- boolean enable = currentCall != null && currentCall.getState() == State.StreamsRunning;
- findViewById(R.id.incallNumpadShow).setEnabled(enable);
- }
-
- private void updateCalleeImage() {
- ImageView view = (ImageView) findViewById(R.id.incall_picture);
- LinphoneCall currentCall = lc().getCurrentCall();
-
- if (currentCall == null || lc().getCallsNb() != 1) {
- view.setVisibility(GONE);
- return;
- }
-
- setCalleePicture(view, currentCall.getRemoteAddress());
- view.setVisibility(VISIBLE);
- }
-
- private void acceptCallUpdate(boolean accept, int id) {
- removeDialog(id);
- timer.cancel();
-
- LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
- if (call == null)
- return;
-
- LinphoneCallParams params = call.getCurrentParamsCopy();
- if (accept) {
- params.setVideoEnabled(true);
- LinphoneManager.getLc().enableVideo(true, true);
- }
-
- try {
- LinphoneManager.getLc().acceptCallUpdate(call, params);
- } catch (LinphoneCoreException e) {
- e.printStackTrace();
- }
-
- updateUI();
- }
-
- @Override
- protected Dialog onCreateDialog(final int id) {
- switch (id) {
- case promptVideoId:
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.dynamic_video_asking);
- builder.setNegativeButton(R.string.dynamic_video_deny, new
- DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton)
- {
- acceptCallUpdate(false, id);
- }
- });
- builder.setPositiveButton(R.string.dynamic_video_accept, new
- DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton)
- {
- acceptCallUpdate(true, id);
- }
- });
- return builder.create();
- case numpadDialogId:
- Numpad numpad = new Numpad(this, true);
- return new AlertDialog.Builder(this).setView(numpad)
- // .setIcon(R.drawable.logo_linphone_57x57)
- // .setTitle("Send DTMFs")
- .setPositiveButton(R.string.close_button_text, new
- DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton)
- {
- dismissDialog(id);
- }
- })
- .create();
- default:
- throw new IllegalArgumentException("unkown dialog id " + id);
- }
- }
-
- private LinphoneCall mActivateCallOnReturnFromUriPicker;
- private boolean mEnterConferenceOnReturnFromUriPicker;
- private void openUriPicker(String pickerType, int requestCode) {
- if (lc().soundResourcesLocked()) {
- Toast.makeText(this, R.string.not_ready_to_make_new_call, Toast.LENGTH_LONG).show();
- return;
- }
- mActivateCallOnReturnFromUriPicker = lc().getCurrentCall();
- mEnterConferenceOnReturnFromUriPicker = lc().isInConference();
- pauseCurrentCallOrLeaveConference();
- Intent intent = new Intent().setClass(this, UriPickerActivity.class);
- intent.putExtra(UriPickerActivity.EXTRA_PICKER_TYPE, pickerType);
- startActivityForResult(intent, requestCode);
- if (!lc().isMicMuted()) {
- mUnMuteOnReturnFromUriPicker = true;
- lc().muteMic(true);
- ((Checkable) findViewById(R.id.toggleMuteMic)).setChecked(true);
- }
- }
-
-
- @Override
- public boolean onLongClick(View v) {
- if (v.getId() == R.id.conf_header || v.getId() == R.id.conf_header_details) {
- if (!lc().isInConference()) {
- // make sure we are in the conference
- // especially due to the difficulty to aim at the detail button.
- lc().enterConference();
- }
- LinphoneActivity.instance().startConferenceDetailsActivity();
- return true;
- }
- return false;
- }
-
- private void enterConferenceAndVirtualConfView(boolean enterConf) {
- if (enterConf) {
- boolean success = lc().enterConference();
- if (success) {
- mConferenceVirtualCallee.setBackgroundResource(R.drawable.conf_callee_active_bg);
- }
- } else {
- lc().leaveConference();
- mConferenceVirtualCallee.setBackgroundResource(R.drawable.conf_callee_bg);
- }
- }
-
- private void terminateCurrentCallOrConferenceOrAll() {
- LinphoneCall currentCall = lc().getCurrentCall();
- if (currentCall != null) {
- lc().terminateCall(currentCall);
- } else if (lc().isInConference()) {
- lc().terminateConference();
- } else {
- lc().terminateAllCalls();
- }
-
- // activity will be closed automatically by LinphoneActivity when no more calls exist
- }
-
- public void onClick(View v) {
- int id = v.getId();
- if (id == R.id.addCall) {
- finish();
- }
- else if (id == R.id.incallHang) {
- terminateCurrentCallOrConferenceOrAll();
- }
- else if (id == R.id.conf_header) {
- boolean enterConf = !lc().isInConference();
- enterConferenceAndVirtualConfView(enterConf);
- }
- else if (id == R.id.conf_header_details) {
- onLongClick(v);
- }
- else if (id == R.id.incallNumpadShow) {
- showDialog(numpadDialogId);
- }
- else if (id == R.id.conf_simple_merge) {
- if (!lc().soundResourcesLocked()) {
- lc().addAllToConference();
- }
- }
- else if (id == R.id.conf_simple_pause) {
- LinphoneCall call = lc().getCurrentCall();
- if (call != null) {
- lc().pauseCall(call);
- } else {
- ((Checkable) v).setChecked(true);
- List pausedCalls = LinphoneUtils.getCallsInState(lc(), Arrays.asList(State.Paused));
- if (pausedCalls.size() == 1) {
- LinphoneCall callToResume = pausedCalls.get(0);
- lc().resumeCall(callToResume);
- }
- }
- }
- else if (id == R.id.conf_simple_video) {
- LinphoneCall vCall = lc().getCurrentCall();
- if (vCall != null) {
- if (!vCall.cameraEnabled() && vCall.getCurrentParamsCopy().getVideoEnabled()) {
- // NoWebcam mode, we let it this way
- LinphoneActivity.instance().startVideoActivity(vCall, 0);
- }
- else if (!LinphoneManager.getInstance().addVideo()) {
- LinphoneActivity.instance().startVideoActivity(vCall, 0);
- }
- }
- }
- else {
- // mic, speaker
- super.onClick(v);
- }
- }
-
-// private void doTransfer() {
-// LinphoneCall tCall = lc().getCurrentCall();
-// if (tCall != null) {
-// prepareForTransferingExistingOrNewCall(tCall);
-// }
-// }
-
- private void prepareForTransferingExistingOrNewCall(final LinphoneCall call) {
- // Include inconf calls
- final List existingCalls = LinphoneUtils.getLinphoneCalls(lc());
- if (existingCalls.size() == 1) {
- // Only possible choice is transfer to new call: doing it directly.
- mCallToTransfer = call;
- openUriPicker(UriPickerActivity.EXTRA_PICKER_TYPE_TRANSFER, transferCallId);
- return;
- }
- existingCalls.remove(call);
- final List numbers = new ArrayList(existingCalls.size() + 1);
- Resources r = getResources();
- for(LinphoneCall c : existingCalls) {
- numbers.add(LinphoneManager.extractADisplayName(r, c.getRemoteAddress()));
- }
- numbers.add(getString(R.string.transfer_to_new_call));
- ListAdapter adapter = new ArrayAdapter(IncallActivity.this, android.R.layout.select_dialog_item, numbers);
- DialogInterface.OnClickListener l = new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- if (which == numbers.size() -1) {
- // Last one is transfer to new call
- mCallToTransfer = call;
- openUriPicker(UriPickerActivity.EXTRA_PICKER_TYPE_TRANSFER, transferCallId);
- } else {
- lc().transferCallToAnother(call, existingCalls.get(which));
- }
- }
- };
- new AlertDialog.Builder(IncallActivity.this).setTitle(R.string.transfer_dialog_title).setAdapter(adapter, l).create().show();
- }
-
- private class CallActionListener implements OnClickListener {
- private LinphoneCall call;
- private Dialog dialog;
- public CallActionListener(LinphoneCall call, Dialog dialog) {
- this.call = call;
- this.dialog = dialog;
- }
- public void onClick(View v) {
- int id =v.getId();
- if (id == R.id.merge_to_conference) {
- lc().addToConference(call);
- }
- else if (id == R.id.terminate_call) {
- lc().terminateCall(call);
- }
- else if (id == R.id.transfer_existing) {
- prepareForTransferingExistingOrNewCall(call);
- }
- else if (id == R.id.transfer_new) {
- openUriPicker(UriPickerActivity.EXTRA_PICKER_TYPE_TRANSFER, transferCallId);
- mCallToTransfer = call;
- }
- else if (id == R.id.addVideo) {
- if (!call.cameraEnabled() && call.getCurrentParamsCopy().getVideoEnabled()) {
- // NoWebcam mode, we let it this way
- LinphoneActivity.instance().startVideoActivity(call, 0);
- }
- else if (!LinphoneManager.getInstance().addVideo()) {
- LinphoneActivity.instance().startVideoActivity(call, 0);
- }
- }
- else if (id == R.id.set_auth_token_verified) {
- call.setAuthenticationTokenVerified(true);
- }
- else if (id == R.id.set_auth_token_not_verified) {
- call.setAuthenticationTokenVerified(false);
- }
- else if (id == R.id.encrypted) {
- call.setAuthenticationTokenVerified(!call.isAuthenticationTokenVerified());
- }
- else {
- throw new RuntimeException("unknown id " + v.getId());
- }
- if (dialog != null) dialog.dismiss();
- }
- }
-
- private class IncallListAdapter extends CalleeListAdapter {
- private boolean aConferenceIsPossible() {
- if (lc().getCallsNb() < 2) {
- return false;
- }
- int count = 0;
- boolean aConfExists = lc().getConferenceSize() > 0;
- for (LinphoneCall call : getSpecificCalls()) {
- final LinphoneCall.State state = call.getState();
- boolean connectionEstablished = state == State.StreamsRunning
- || state == State.Paused
- || state == State.PausedByRemote;
- if (connectionEstablished)
- count++;
- if ((aConfExists && count >= 1) || count >= 2)
- return true;
- }
- return false;
- }
-
- private Collection mStatesToHighlight = Arrays.asList(
- State.StreamsRunning,
- State.OutgoingRinging,
- State.OutgoingEarlyMedia,
- State.OutgoingInit,
- State.OutgoingProgress);
-
- public View getView(int position, View v, ViewGroup parent) {
- if (v == null) {
- if (Version.sdkAboveOrEqual(Version.API06_ECLAIR_201)) {
- v = getLayoutInflater().inflate(R.layout.conf_callee, null);
- } else {
- v = getLayoutInflater().inflate(R.layout.conf_callee_older_devices, null);
- }
- }
-
- final LinphoneCall call = getItem(position);
- final LinphoneCall.State state = call.getState();
-
- LinphoneAddress address = call.getRemoteAddress();
- TextView mainTextView = (TextView) v.findViewById(R.id.name);
- if (!TextUtils.isEmpty(address.getDisplayName())) {
- mainTextView.setText(address.getDisplayName());
- } else {
- mainTextView.setText(address.getUserName());
- }
- String statusLabel = getStateText(state);
- ((TextView) v.findViewById(R.id.address)).setText(statusLabel);
-
-
- boolean highlighted = mStatesToHighlight.contains(state);
-
- int bgDrawableId = R.drawable.conf_callee_selector_normal;
- if (state == State.IncomingReceived) {
- bgDrawableId = R.drawable.conf_callee_selector_incoming;
- } else if (highlighted) {
- bgDrawableId = R.drawable.conf_callee_selector_active;
- }
- v.setBackgroundResource(bgDrawableId);
-
- final boolean connectionEstablished = state == State.StreamsRunning
- || state == State.Paused
- || state == State.PausedByRemote;
-
- boolean statusPaused = state== State.Paused || state == State.PausedByRemote;
- setVisibility(v, R.id.callee_status_paused, statusPaused);
- setVisibility(v, R.id.callee_status_qos, !statusPaused);
-
- final OnLongClickListener showCallActionsLongListener = new OnLongClickListener() {
- public boolean onLongClick(View v) {
- if (lc().soundResourcesLocked()) {
- return false;
- }
- View content = getLayoutInflater().inflate(R.layout.conf_choices_dialog, null);
- Dialog dialog = new AlertDialog.Builder(IncallActivity.this).setView(content).create();
- OnClickListener l = new CallActionListener(call, dialog);
- enableView(content, R.id.transfer_existing, l, mAllowTransfers && getSpecificCalls().size() >=2);
- enableView(content, R.id.transfer_new, l, mAllowTransfers);
- boolean showMergeToConf = connectionEstablished && aConferenceIsPossible();
- enableView(content, R.id.merge_to_conference, l, showMergeToConf);
- enableView(content, R.id.terminate_call, l, true);
-
- if (call.getCurrentParamsCopy().getMediaEncryption()==MediaEncryption.ZRTP) {
- boolean authVerified = call.isAuthenticationTokenVerified();
- String fmt = getString(authVerified ? R.string.reset_sas_fmt : R.string.verify_sas_fmt);
- TextView token = (TextView) content.findViewById(R.id.authentication_token);
- token.setText(String.format(fmt, call.getAuthenticationToken()));
- enableView(content, R.id.set_auth_token_not_verified, l, authVerified);
- enableView(content, R.id.set_auth_token_verified, l, !authVerified);
- enableView(content, R.id.encrypted, l, true);
- } else {
- setVisibility(content, R.id.encrypted, false);
- }
-
- dialog.show();
- return true;
- }
- };
- v.setOnLongClickListener(showCallActionsLongListener);
-
- OnClickListener showCallActionsSimpleListener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- showCallActionsLongListener.onLongClick(v);
- }
- };
-
- MediaEncryption mediaEncryption = call.getCurrentParamsCopy().getMediaEncryption();
- if (MediaEncryption.None == mediaEncryption) {
- setVisibility(v, R.id.callee_status_secured, false);
- setVisibility(v, R.id.callee_status_maybe_secured, false);
- setVisibility(v, R.id.callee_status_not_secured, false);
- } else if (MediaEncryption.ZRTP == mediaEncryption ) {
- boolean reallySecured = call.isAuthenticationTokenVerified();
- enableView(v, R.id.callee_status_secured, showCallActionsSimpleListener, reallySecured);
- enableView(v, R.id.callee_status_maybe_secured, showCallActionsSimpleListener, !reallySecured);
- enableView(v, R.id.callee_status_not_secured, showCallActionsSimpleListener, false);
- } else {
- setVisibility(v, R.id.callee_status_secured, true);
- setVisibility(v, R.id.callee_status_maybe_secured, false);
- setVisibility(v, R.id.callee_status_not_secured, false);
- }
-
- v.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- State actualState = call.getState();
- if (State.StreamsRunning == actualState) {
- lc().pauseCall(call);
- } else if (State.PausedByRemote == actualState) {
- String msg = getString(R.string.cannot_resume_paused_by_remote_call);
- Toast.makeText(IncallActivity.this, msg, Toast.LENGTH_SHORT).show();
- } else if (lc().soundResourcesLocked()) {
- return;
- } else if (State.Paused == actualState) {
- if (call != null && call.cameraEnabled() && call.getCurrentParamsCopy().getVideoEnabled())
- {
- finish();
- LinphoneActivity.instance().startVideoActivity(call, 0);
- }
- lc().resumeCall(call);
- }
- }
- });
-
- ImageView pictureView = (ImageView) v.findViewById(R.id.picture);
- if (lc().getCallsNb() != 1) {
- // May be greatly sped up using a drawable cache
- setCalleePicture(pictureView, address);
- } else {
- pictureView.setVisibility(GONE);
- }
-
- registerCallDurationTimer(v, call);
- registerCallQualityListener(v, call);
-
- enableView(v, R.id.callee_status_details, showCallActionsSimpleListener, true);
-
- return v;
- }
- }
-
- private String getStateText(State state) {
- int id;
- if (state == State.StreamsRunning) {
- id=R.string.status_active_call;
- } else if (state == State.Paused) {
- id=R.string.state_paused;
- } else if (state == State.PausedByRemote) {
- id=R.string.state_paused_by_remote;
- } else 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.OutgoingProgress) {
- id=R.string.state_outgoing_progress;
- } else {
- return "";
- }
- return getString(id);
- }
-
- private void updatePauseMergeButtons() {
- View controls = findViewById(R.id.incall_controls_layout);
-
- int nbCalls = lc().getCallsNb();
- View pauseView = controls.findViewById(R.id.conf_simple_pause);
- View mergeView = controls.findViewById(R.id.conf_simple_merge);
-
- if (nbCalls <= 1) {
- ((Checkable) pauseView).setChecked(lc().getCurrentCall() == null);
- mergeView.setVisibility(GONE);
- pauseView.setVisibility(VISIBLE);
-
- } else {
- int nonConfCallsNb = LinphoneUtils.countNonConferenceCalls(lc());
- boolean enableMerge = nonConfCallsNb >=2;
- enableMerge |= nonConfCallsNb >=1 && lc().getConferenceSize() > 0;
- mergeView.setEnabled(enableMerge);
- pauseView.setVisibility(GONE);
- mergeView.setVisibility(VISIBLE);
- }
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig)
- {
- if (!Version.isXLargeScreen(this))
- {
- // Do nothing to not recreate the activity on smartphone if screen is rotated
- super.onConfigurationChanged(null);
- return;
- }
- super.onConfigurationChanged(newConfig);
- }
-
- private void updateConfItem() {
- boolean confExists = lc().getConferenceSize() > 0;
- View confView = findViewById(R.id.conf_header);
- confView.setVisibility(confExists? VISIBLE : GONE);
-
- if (confExists) {
- if (lc().isInConference()) {
- confView.setBackgroundResource(R.drawable.conf_callee_selector_active);
- } else {
- confView.setBackgroundResource(R.drawable.conf_callee_selector_normal);
- }
- }
- }
-
- protected void updateUI() {
- updatePauseMergeButtons();
- updateCalleeImage();
- updateSoundLock();
- updateAddCallButton();
- updateNumpadButton();
- updateConfItem();
-
- super.updateUI();
- }
-
- 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 = c2.getDuration() - c1.getDuration();
- return durationDiff;
-
- }
-
- private boolean checkValidTargetUri(String uri) {
- boolean invalidUri;
- try {
- String target = lc().interpretUrl(uri).asStringUriOnly();
- invalidUri = lc().isMyself(target);
- } catch (LinphoneCoreException e) {
- invalidUri = true;
- }
-
- if (invalidUri) {
- String msg = String.format(getString(R.string.bad_target_uri), uri);
- Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
- return false;
- }
- return true;
- }
-
- private LinphoneCall mCallToTransfer;
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (mUnMuteOnReturnFromUriPicker) {
- lc().muteMic(false);
- ((Checkable) findViewById(R.id.toggleMuteMic)).setChecked(false);
- }
-
- String uri = null;
- if (data != null) {
- uri = data.getStringExtra(UriPickerActivity.EXTRA_CALLEE_URI);
- }
- if (resultCode != RESULT_OK || TextUtils.isEmpty(uri)) {
- mCallToTransfer = null;
- eventuallyResumeConfOrCallOnPickerReturn(true);
- return;
- }
-
-
- if (!checkValidTargetUri(uri)) {
- eventuallyResumeConfOrCallOnPickerReturn(true);
- return;
- }
-
- if (lc().soundResourcesLocked()) {
- Toast.makeText(this, R.string.not_ready_to_make_new_call, Toast.LENGTH_LONG).show();
- eventuallyResumeConfOrCallOnPickerReturn(true);
- return;
- }
-
- switch (requestCode) {
- case addCallId:
- try {
- lc().invite(uri);
- eventuallyResumeConfOrCallOnPickerReturn(false);
- } catch (LinphoneCoreException e) {
- Log.e(e);
- Toast.makeText(this, R.string.error_adding_new_call, Toast.LENGTH_LONG).show();
- }
- break;
- case transferCallId:
- lc().transferCall(mCallToTransfer, uri);
- // don't re-enter conference if call to transfer from conference
- boolean doResume = !mCallToTransfer.isInConference();
- // don't resume call if it is the call to transfer
- doResume &= mActivateCallOnReturnFromUriPicker != mCallToTransfer;
- eventuallyResumeConfOrCallOnPickerReturn(doResume);
- Toast.makeText(this, R.string.transfer_started, Toast.LENGTH_LONG).show();
- break;
- default:
- throw new RuntimeException("unhandled request code " + requestCode);
- }
- }
-
- private void eventuallyResumeConfOrCallOnPickerReturn(boolean doCallConfResuming) {
- if (doCallConfResuming) {
- if (mActivateCallOnReturnFromUriPicker != null) {
- lc().resumeCall(mActivateCallOnReturnFromUriPicker);
- } else if (mEnterConferenceOnReturnFromUriPicker) {
- enterConferenceAndVirtualConfView(true);
- }
- }
- mActivateCallOnReturnFromUriPicker = null;
- mEnterConferenceOnReturnFromUriPicker = false;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (LinphoneUtils.onKeyVolumeAdjust(keyCode)) return true;
- if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) return true;
- return super.onKeyDown(keyCode, event);
- }
-
-
- private Handler mHandler = new Handler();
- @Override
- public void onCallEncryptionChanged(LinphoneCall call, boolean encrypted,
- String authenticationToken) {
- mHandler.post(new Runnable() {
- public void run() {
- updateUI();
- }
- });
- }
-
- @Override
- public void onCallStateChanged(LinphoneCall call, final State state, String message) {
- if (state == State.CallUpdatedByRemote) {
- // If the correspondent proposes video while audio call
- boolean remoteVideo = call.getRemoteParams().getVideoEnabled();
- boolean localVideo = call.getCurrentParamsCopy().getVideoEnabled();
- boolean autoAcceptCameraPolicy = LinphoneManager.getInstance().isAutoAcceptCamera();
- if (remoteVideo && !localVideo && !autoAcceptCameraPolicy && !LinphoneManager.getLc().isInConference()) {
- mHandler.post(new Runnable() {
- public void run() {
- showDialog(promptVideoId);
- // We let 30 secs for the user to decide
- timer = new CountDownTimer(30000, 1000) {
- public void onTick(long millisUntilFinished) { }
-
- public void onFinish() {
- acceptCallUpdate(false, promptVideoId);
- }
- }.start();
- }
- });
- }
- }
- super.onCallStateChanged(call, state, message);
- }
-}
diff --git a/src/org/linphone/IncomingCallActivity.java b/src/org/linphone/IncomingCallActivity.java
index f7afc26fc..932057d91 100644
--- a/src/org/linphone/IncomingCallActivity.java
+++ b/src/org/linphone/IncomingCallActivity.java
@@ -23,16 +23,15 @@ import java.util.List;
import org.linphone.LinphoneSimpleListener.LinphoneOnCallStateChangedListener;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
-import org.linphone.core.Log;
import org.linphone.core.LinphoneCall.State;
-import org.linphone.ui.SlidingTab;
-import org.linphone.ui.SlidingTab.OnTriggerListener;
+import org.linphone.core.Log;
+import org.linphone.ui.LinphoneSliders;
+import org.linphone.ui.LinphoneSliders.LinphoneSliderTriggered;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
-import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
@@ -44,13 +43,13 @@ import android.widget.Toast;
*
* @author Guillaume Beraudo
*/
-public class IncomingCallActivity extends Activity implements LinphoneOnCallStateChangedListener, OnTriggerListener {
+public class IncomingCallActivity extends Activity implements LinphoneOnCallStateChangedListener, LinphoneSliderTriggered {
private TextView mNameView;
private TextView mNumberView;
private ImageView mPictureView;
private LinphoneCall mCall;
- private SlidingTab mIncomingCallWidget;
+ private LinphoneSliders mIncomingCallWidget;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -67,13 +66,7 @@ public class IncomingCallActivity extends Activity implements LinphoneOnCallStat
// "Dial-to-answer" widget for incoming calls.
- mIncomingCallWidget = (SlidingTab) findViewById(R.id.sliding_widget);
-
- // For now, we only need to show two states: answer and decline.
- // TODO: make left hint work
-// mIncomingCallWidget.setLeftHintText(R.string.slide_to_answer_hint);
-// mIncomingCallWidget.setRightHintText(R.string.slide_to_decline_hint);
-
+ mIncomingCallWidget = (LinphoneSliders) findViewById(R.id.sliding_widget);
mIncomingCallWidget.setOnTriggerListener(this);
@@ -100,7 +93,7 @@ public class IncomingCallActivity extends Activity implements LinphoneOnCallStat
LinphoneAddress address = mCall.getRemoteAddress();
// May be greatly sped up using a drawable cache
Uri uri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, getContentResolver());
- LinphoneUtils.setImagePictureFromUri(this, mPictureView, uri, R.drawable.unknown_person);
+ LinphoneUtils.setImagePictureFromUri(this, mPictureView, uri, R.drawable.unknown_small);
// To be done after findUriPictureOfContactAndSetDisplayName called
mNameView.setText(address.getDisplayName());
@@ -142,29 +135,21 @@ public class IncomingCallActivity extends Activity implements LinphoneOnCallStat
Toast.makeText(this, R.string.couldnt_accept_call, Toast.LENGTH_LONG);
} else {
if (mCall.getCurrentParamsCopy().getVideoEnabled())
- LinphoneActivity.instance().startVideoActivity(mCall, 0);
+ LinphoneActivity.instance().startVideoActivity(mCall);
else
- LinphoneActivity.instance().startIncallActivity();
- }
- }
- @Override
- public void onGrabbedStateChange(View v, int grabbedState) {
- }
-
- @Override
- public void onTrigger(View v, int whichHandle) {
- switch (whichHandle) {
- case OnTriggerListener.LEFT_HANDLE:
- answer();
- finish();
- break;
- case OnTriggerListener.RIGHT_HANDLE:
- decline();
- finish();
- break;
- default:
- break;
+ LinphoneActivity.instance().startIncallActivity(mCall);
}
}
+ @Override
+ public void onLeftHandleTriggered() {
+ answer();
+ finish();
+ }
+
+ @Override
+ public void onRightHandleTriggered() {
+ decline();
+ finish();
+ }
}
diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java
index 755b9b0a9..d0bc93a89 100644
--- a/src/org/linphone/LinphoneActivity.java
+++ b/src/org/linphone/LinphoneActivity.java
@@ -1,6 +1,7 @@
+package org.linphone;
/*
LinphoneActivity.java
-Copyright (C) 2010 Belledonne Communications, Grenoble, France
+Copyright (C) 2012 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
@@ -16,64 +17,70 @@ 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 static android.content.Intent.ACTION_MAIN;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import org.linphone.LinphoneManager.AddressType;
import org.linphone.LinphoneSimpleListener.LinphoneOnCallStateChangedListener;
+import org.linphone.LinphoneSimpleListener.LinphoneOnMessageReceivedListener;
+import org.linphone.LinphoneSimpleListener.LinphoneOnRegistrationStateChangedListener;
import org.linphone.compatibility.Compatibility;
+import org.linphone.core.CallDirection;
+import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
-import org.linphone.core.LinphoneCore;
+import org.linphone.core.LinphoneCallLog;
+import org.linphone.core.LinphoneCallLog.CallStatus;
import org.linphone.core.LinphoneCore.RegistrationState;
+import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.Log;
-import org.linphone.mediastream.Version;
+import org.linphone.setup.SetupActivity;
+import org.linphone.ui.AddressText;
-import android.app.AlertDialog;
-import android.app.TabActivity;
-import android.content.Context;
-import android.content.DialogInterface;
+import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
-import android.text.Html;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.OrientationEventListener;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.Fragment.SavedState;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
import android.view.WindowManager;
-import android.widget.TabHost.TabSpec;
-import android.widget.TabWidget;
+import android.widget.ImageView;
import android.widget.TextView;
-import android.widget.Toast;
-
-public class LinphoneActivity extends TabActivity implements ContactPicked
- , LinphoneOnCallStateChangedListener
- {
- public static final String DIALER_TAB = "dialer";
+
+/**
+ * @author Sylvain Berfini
+ */
+public class LinphoneActivity extends FragmentActivity implements OnClickListener, ContactPicked,
+ LinphoneOnCallStateChangedListener,
+ LinphoneOnMessageReceivedListener,
+ LinphoneOnRegistrationStateChangedListener {
public static final String PREF_FIRST_LAUNCH = "pref_first_launch";
- private static final int video_activity = 100;
+ private static final int SETTINGS_ACTIVITY = 123;
private static final int FIRST_LOGIN_ACTIVITY = 101;
- private static final int INCOMING_CALL_ACTIVITY = 103;
- private static final int incall_activity = 104;
- private static final int conferenceDetailsActivity = 105;
- private static final String PREF_CHECK_CONFIG = "pref_check_config";
-
+ private static final int callActivity = 19;
private static LinphoneActivity instance;
- private OrientationEventListener mOrientationHelper;
+ private StatusFragment statusFragment;
+ private TextView missedCalls;
+ private ImageView history, contacts, dialer, settings, chat;
+ private FragmentsAvailable currentFragment;
+ private Fragment dialerFragment, messageListenerFragment;
+ private SavedState dialerSavedState;
+ private ChatStorage chatStorage;
private Handler mHandler = new Handler();
-
- // Customization
- private static boolean useFirstLoginActivity;
- private static boolean useMenuSettings;
- private static boolean useMenuAbout;
- private boolean checkAccount;
+ private boolean isInCallLayout = false;
static final boolean isInstanciated() {
return instance != null;
@@ -81,511 +88,528 @@ public class LinphoneActivity extends TabActivity implements ContactPicked
public static final LinphoneActivity instance() {
if (instance != null) return instance;
-
throw new RuntimeException("LinphoneActivity not instantiated yet");
}
-
- public void onCreate(Bundle savedInstanceState) {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- if (Version.isXLargeScreen(this)) {
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- }
-
- if (!LinphoneManager.isInstanciated()) {
+
+ if (!LinphoneManager.isInstanciated()) {
Log.e("No service running: avoid crash by starting the launcher", this.getClass().getName());
// super.onCreate called earlier
finish();
startActivity(getIntent().setClass(this, LinphoneLauncherActivity.class));
return;
}
- instance = this;
- setContentView(R.layout.main);
-
- @SuppressWarnings("deprecation")
- int rotation = Compatibility.getRotation(getWindowManager().getDefaultDisplay());
- // Inverse landscape rotation to initiate linphoneCore correctly
- if (rotation == 270)
- rotation = 90;
- else if (rotation == 90)
- rotation = 270;
-
- LinphoneManager.getLc().setDeviceRotation(rotation);
- mAlwaysChangingPhoneAngle = rotation;
-
- LinphonePreferenceManager.getInstance(this);
- useFirstLoginActivity = getResources().getBoolean(R.bool.useFirstLoginActivity);
- useMenuSettings = getResources().getBoolean(R.bool.useMenuSettings);
- useMenuAbout = getResources().getBoolean(R.bool.useMenuAbout);
- checkAccount = !useFirstLoginActivity;
-
- SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
-
- if (!useFirstLoginActivity || pref.getBoolean(getString(R.string.first_launch_suceeded_once_key), false)) {
- fillTabHost();
- } else {
- startActivityForResult(new Intent().setClass(this, FirstLoginActivity.class), FIRST_LOGIN_ACTIVITY);
+
+ boolean useFirstLoginActivity = getResources().getBoolean(R.bool.useFirstLoginActivity);
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
+ if (useFirstLoginActivity && !pref.getBoolean(getString(R.string.first_launch_suceeded_once_key), false)) {
+ startActivityForResult(new Intent().setClass(this, SetupActivity.class), FIRST_LOGIN_ACTIVITY);
}
- if (checkAccount && !useFirstLoginActivity) {
- if (pref.getBoolean(PREF_FIRST_LAUNCH, true)) {
- onFirstLaunch();
- } else if (!pref.getBoolean(PREF_CHECK_CONFIG, false)
- && !checkDefined(pref, R.string.pref_username_key, R.string.pref_domain_key)) {
- onBadSettings(pref);
- } else {
- checkAccount = false;
- }
+ setContentView(R.layout.main);
+ initButtons();
+
+ if (LinphoneManager.isInstanciated()) {
+ LinphoneManager.addListener(this);
}
-
- LinphoneManager.addListener(this);
+
+ if (findViewById(R.id.fragmentContainer) != null) {
+ if (savedInstanceState != null) {
+ return;
+ }
+
+ dialerFragment = new DialerFragment();
+ dialerFragment.setArguments(getIntent().getExtras());
+ getSupportFragmentManager().beginTransaction()
+ .add(R.id.fragmentContainer, dialerFragment).commit();
+ currentFragment = FragmentsAvailable.DIALER;
+ }
+
+ int missedCalls = LinphoneManager.getLc().getMissedCallsCount();
+ displayMissedCalls(missedCalls);
+
+ instance = this;
}
+ private void initButtons() {
+ history = (ImageView) findViewById(R.id.history);
+ history.setOnClickListener(this);
+ contacts = (ImageView) findViewById(R.id.contacts);
+ contacts.setOnClickListener(this);
+ dialer = (ImageView) findViewById(R.id.dialer);
+ dialer.setOnClickListener(this);
+ dialer.setSelected(true);
+ settings = (ImageView) findViewById(R.id.settings);
+ settings.setOnClickListener(this);
+ chat = (ImageView) findViewById(R.id.chat);
+ chat.setOnClickListener(this);
+ missedCalls = (TextView) findViewById(R.id.missedCalls);
+ }
+ private void changeCurrentFragment(FragmentsAvailable newFragmentType, Bundle extras) {
+ if (newFragmentType == currentFragment && newFragmentType != FragmentsAvailable.CHAT) {
+ return;
+ }
+
+ if (currentFragment == FragmentsAvailable.DIALER) {
+ dialerSavedState = getSupportFragmentManager().saveFragmentInstanceState(dialerFragment);
+ }
+
+ Fragment newFragment = null;
+
+ switch (newFragmentType) {
+ case HISTORY:
+ newFragment = new HistoryFragment();
+ break;
+ case HISTORY_DETAIL:
+ newFragment = new HistoryDetailFragment();
+ break;
+ case CONTACTS:
+ newFragment = new ContactsFragment();
+ break;
+ case CONTACT:
+ newFragment = new ContactFragment();
+ break;
+ case DIALER:
+ newFragment = new DialerFragment();
+ if (extras == null) {
+ newFragment.setInitialSavedState(dialerSavedState);
+ }
+ dialerFragment = newFragment;
+ break;
+ case SETTINGS:
+ break;
+ case CHAT:
+ newFragment = new ChatFragment();
+ messageListenerFragment = newFragment;
+ break;
+ case CHATLIST:
+ newFragment = new ChatListFragment();
+ break;
+ }
+
+ if (newFragment != null) {
+ newFragment.setArguments(extras);
+ changeFragment(newFragment, newFragmentType);
+ }
+ }
+
+ private void changeFragment(Fragment newFragment, FragmentsAvailable newFragmentType) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+
+ if (currentFragment.shouldAddToBackStack()) {
+ if (!getResources().getBoolean(R.bool.disable_animations) && currentFragment.shouldAnimate()) {
+ if (newFragmentType.isRightOf(currentFragment)) {
+ transaction.setCustomAnimations(R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left, R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right);
+ } else {
+ transaction.setCustomAnimations(R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right, R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left);
+ }
+ }
+ transaction.addToBackStack("Add to back stack");
+ }
+ else {
+ try {
+ getSupportFragmentManager().popBackStack("Add to back stack", FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ } catch (java.lang.IllegalStateException e) {
+
+ }
+ }
+ transaction.replace(R.id.fragmentContainer, newFragment);
+
+ transaction.commitAllowingStateLoss();
+ currentFragment = newFragmentType;
+ }
+
+ public void displayHistoryDetail(String sipUri, LinphoneCallLog log) {
+ LinphoneAddress lAddress = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri);
+ Uri uri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, getContentResolver());
+
+ Bundle extras = new Bundle();
+ extras.putString("SipUri", sipUri);
+ if (lAddress.getDisplayName() != null) {
+ extras.putString("DisplayName", lAddress.getDisplayName());
+ extras.putString("PictureUri", uri.toString());
+ }
+
+ String status;
+ if (log.getDirection() == CallDirection.Outgoing) {
+ status = "Outgoing";
+ } else {
+ if (log.getStatus() == CallStatus.Missed) {
+ status = "Missed";
+ } else {
+ status = "Incoming";
+ }
+ }
+ extras.putString("CallStatus", status);
+ extras.putString("CallTime", secondsToDisplayableString(log.getCallDuration()));
+ extras.putString("CallDate", log.getStartDate());
+
+ changeCurrentFragment(FragmentsAvailable.HISTORY_DETAIL, extras);
+ }
+
+ private String secondsToDisplayableString(int secs) {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
+ Calendar cal = Calendar.getInstance();
+ cal.set(0, 0, 0, 0, 0, secs);
+ return dateFormat.format(cal.getTime());
+ }
+
+ public void displayContact(Contact contact) {
+ Bundle extras = new Bundle();
+ extras.putSerializable("Contact", contact);
+ changeCurrentFragment(FragmentsAvailable.CONTACT, extras);
+ }
+
+ public void displayChat(String sipUri) {
+ LinphoneAddress lAddress = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri);
+ Uri uri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, getContentResolver());
+
+ Bundle extras = new Bundle();
+ extras.putString("SipUri", sipUri);
+ if (lAddress.getDisplayName() != null) {
+ extras.putString("DisplayName", lAddress.getDisplayName());
+ extras.putString("PictureUri", uri.toString());
+ }
+ changeCurrentFragment(FragmentsAvailable.CHAT, extras);
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+ resetSelection();
+
+ if (id == R.id.history) {
+ changeCurrentFragment(FragmentsAvailable.HISTORY, null);
+ history.setSelected(true);
+ LinphoneManager.getLc().resetMissedCallsCount();
+ displayMissedCalls(0);
+ }
+ else if (id == R.id.contacts) {
+ changeCurrentFragment(FragmentsAvailable.CONTACTS, null);
+ contacts.setSelected(true);
+ }
+ else if (id == R.id.dialer) {
+ changeCurrentFragment(FragmentsAvailable.DIALER, null);
+ dialer.setSelected(true);
+ }
+ else if (id == R.id.settings) {
+// if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
+// changeCurrentFragment(FragmentsAvailable.SETTINGS, null);
+// settings.setSelected(true);
+// } else {
+ Intent intent = new Intent(ACTION_MAIN);
+ intent.setClass(this, PreferencesActivity.class);
+ startActivityForResult(intent, SETTINGS_ACTIVITY);
+ if (FragmentsAvailable.SETTINGS.isRightOf(currentFragment)) {
+ Compatibility.overridePendingTransition(this, R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left);
+ } else {
+ Compatibility.overridePendingTransition(this, R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right);
+ }
+// }
+ }
+ else if (id == R.id.chat) {
+ changeCurrentFragment(FragmentsAvailable.CHATLIST, null);
+ chat.setSelected(true);
+ }
+ }
+
+ private void resetSelection() {
+ history.setSelected(false);
+ contacts.setSelected(false);
+ dialer.setSelected(false);
+ settings.setSelected(false);
+ chat.setSelected(false);
+ }
+
+ public void selectMenu(FragmentsAvailable menuToSelect) {
+ currentFragment = menuToSelect;
+ resetSelection();
+
+ switch (menuToSelect) {
+ case HISTORY:
+ case HISTORY_DETAIL:
+ history.setSelected(true);
+ break;
+ case CONTACTS:
+ case CONTACT:
+ contacts.setSelected(true);
+ break;
+ case DIALER:
+ dialer.setSelected(true);
+ break;
+ case SETTINGS:
+ settings.setSelected(true);
+ break;
+ case CHAT:
+ case CHATLIST:
+ chat.setSelected(true);
+ break;
+ }
+ }
+
+ public void updateDialerFragment(DialerFragment fragment) {
+ dialerFragment = fragment;
+ // Hack to maintain ADJUST_PAN flag
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public void updateChatFragment(ChatFragment fragment) {
+ messageListenerFragment = fragment;
+ // Hack to maintain ADJUST_PAN flag
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public void updateStatusFragment(StatusFragment fragment) {
+ statusFragment = fragment;
+
+ if (LinphoneManager.getLc().getDefaultProxyConfig() != null) {
+ statusFragment.registrationStateChanged(LinphoneManager.getLc().getDefaultProxyConfig().getState());
+ }
+ }
+
+ public StatusFragment getStatusFragment() {
+ return statusFragment;
+ }
+
+ public ArrayList getChatList() {
+ if (chatStorage != null) {
+ return chatStorage.getChatList();
+ }
+ return null;
+ }
+
+ public List getChatMessages(String correspondent) {
+ if (chatStorage == null) {
+ chatStorage = new ChatStorage(this);
+ }
+
+ return chatStorage.getMessages(correspondent);
+ }
+
+ public void removeFromChatList(String sipUri) {
+ if (chatStorage == null) {
+ chatStorage = new ChatStorage(this);
+ }
+
+ chatStorage.removeDiscussion(sipUri);
+ }
+
+ @Override
+ public void onMessageReceived(LinphoneAddress from, String message) {
+ if (chatStorage == null) {
+ chatStorage = new ChatStorage(this);
+ }
+
+ chatStorage.saveMessage(from.asStringUriOnly(), "", message);
+
+ Log.d("Message received from " + from + ": " + message);
+ if (messageListenerFragment != null && messageListenerFragment.isVisible()) {
+ ((ChatFragment) messageListenerFragment).onMessageReceived(from, message);
+ }
+
+ if (LinphoneService.isReady()) {
+ LinphoneUtils.findUriPictureOfContactAndSetDisplayName(from, getContentResolver());
+ LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), from.getDisplayName(), message);
+ }
+ }
+
+ public void onMessageSent(String to, String message) {
+ if (chatStorage == null) {
+ chatStorage = new ChatStorage(this);
+ }
+
+ chatStorage.saveMessage("", to, message);
+ Log.d("Message sent to " + to + ": " + message);
+ }
+
+ @Override
+ public void onRegistrationStateChanged(RegistrationState state) {
+ if (statusFragment != null) {
+ statusFragment.registrationStateChanged(state);
+ }
+ }
+
+ private void displayMissedCalls(final int missedCallsCount) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (missedCallsCount > 0) {
+ missedCalls.setText(missedCallsCount + "");
+ missedCalls.setVisibility(View.VISIBLE);
+ } else {
+ missedCalls.setVisibility(View.GONE);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onCallStateChanged(LinphoneCall call, State state,
+ String message) {
+ if (state == State.IncomingReceived) {
+ Intent intent = new Intent(this, IncomingCallActivity.class);
+ startActivity(intent);
+ } else if (state == State.OutgoingInit) {
+ if (call.getCurrentParamsCopy().getVideoEnabled()) {
+ startVideoActivity(call);
+ } else {
+ startIncallActivity(call);
+ }
+ } else if (state == State.CallEnd || state == State.Error || state == State.CallReleased) {
+ resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
+ }
+
+ int missedCalls = LinphoneManager.getLc().getMissedCallsCount();
+ displayMissedCalls(missedCalls);
+ }
+
+ @Override
+ public void setAddresGoToDialerAndCall(String number, String name, Uri photo) {
+ Bundle extras = new Bundle();
+ extras.putString("SipUri", number);
+ extras.putString("DisplayName", name);
+ extras.putString("Photo", photo == null ? null : photo.toString());
+ changeCurrentFragment(FragmentsAvailable.DIALER, extras);
+
+ AddressType address = new AddressText(this, null);
+ address.setDisplayedName(name);
+ address.setText(number);
+ LinphoneManager.getInstance().newOutgoingCall(address);
+ }
+
+ public void setAddressAndGoToDialer(String number) {
+ Bundle extras = new Bundle();
+ extras.putString("SipUri", number);
+ changeCurrentFragment(FragmentsAvailable.DIALER, extras);
+ }
+
+ @Override
+ public void goToDialer() {
+ changeCurrentFragment(FragmentsAvailable.DIALER, null);
+ }
+
+ public void onRegistrationStateChanged(RegistrationState state, String message) {
+ if (statusFragment != null) {
+ statusFragment.registrationStateChanged(state);
+ }
+ }
+
+ public void startVideoActivity(LinphoneCall currentCall) {
+ Intent intent = new Intent(this, InCallActivity.class);
+ intent.putExtra("VideoEnabled", true);
+ startActivityForResult(intent, callActivity);
+ }
+
+ public void startIncallActivity(LinphoneCall currentCall) {
+ Intent intent = new Intent(this, InCallActivity.class);
+ intent.putExtra("VideoEnabled", false);
+ startActivityForResult(intent, callActivity);
+ }
+
+ public void showPreferenceErrorDialog(String message) {
+
+ }
+
+ private void initInCallMenuLayout() {
+ isInCallLayout = true;
+ selectMenu(FragmentsAvailable.DIALER);
+ ((DialerFragment) dialerFragment).resetLayout();
+ }
+
+ public void resetClassicMenuLayoutAndGoBackToCallIfStillRunning() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ isInCallLayout = false;
+ ((DialerFragment) dialerFragment).resetLayout();
+
+ if (LinphoneManager.getLc().getCallsNb() > 0) {
+ LinphoneCall call = LinphoneManager.getLc().getCalls()[0];
+ if (call.getCurrentParamsCopy().getVideoEnabled()) {
+ startVideoActivity(call);
+ } else {
+ startIncallActivity(call);
+ }
+ }
+ }
+ });
+ }
+
+ public boolean isInCallLayout() {
+ return isInCallLayout;
+ }
+
+ public FragmentsAvailable getCurrentFragment() {
+ return currentFragment;
+ }
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case FIRST_LOGIN_ACTIVITY:
- if (resultCode == RESULT_OK) {
-// Toast.makeText(this, getString(R.string.ec_calibration_launch_message), Toast.LENGTH_LONG).show();
-// try {
-// LinphoneManager.getInstance().startEcCalibration(new EcCalibrationListener() {
-// public void onEcCalibrationStatus(EcCalibratorStatus status, int delayMs) {
-// PreferenceManager.getDefaultSharedPreferences(LinphoneActivity.this)
-// .edit().putBoolean(
-// getString(R.string.pref_echo_canceller_calibration_key),
-// status == EcCalibratorStatus.Done).commit();
-// }
-// });
-// } catch (LinphoneCoreException e) {
-// Log.e(e, "Unable to calibrate EC");
-// }
- fillTabHost();
- } else {
+ if (resultCode == Activity.RESULT_FIRST_USER && requestCode == SETTINGS_ACTIVITY) {
+ if (data.getExtras().getBoolean("Exit", false)) {
finish();
stopService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
- }
- break;
- default:
- break;
- }
-
- super.onActivityResult(requestCode, resultCode, data);
- }
-
-
- private synchronized void fillTabHost() {
- if (((TabWidget) findViewById(android.R.id.tabs)).getChildCount() != 0) return;
-
- startActivityInTab("history",
- new Intent().setClass(this, HistoryActivity.class),
- R.string.tab_history, R.drawable.history_orange);
-
-
- startActivityInTab(DIALER_TAB,
- new Intent().setClass(this, DialerActivity.class).setData(getIntent().getData()),
- R.string.tab_dialer, R.drawable.dialer_orange);
-
-
- startActivityInTab("contact",
- new Intent().setClass(this, Version.sdkAboveOrEqual(5) ?
- ContactPickerActivityNew.class : ContactPickerActivityOld.class),
- R.string.tab_contact, R.drawable.contact_orange);
-
-
- selectDialerTab();
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- if (intent.getData() == null) {
- Log.i("LinphoneActivity received an intent without data");
- // Ex: incoming call received
- if (LinphoneManager.getLc().getCallsNb() == 0) return;
- if(LinphoneManager.getLc().isInComingInvitePending()) {
- startIncomingCallActivity();
} else {
- LinphoneCall currentCall = LinphoneManager.getLc().getCurrentCall();
- if (currentCall == null)
- return;
-
- if (currentCall.getCurrentParamsCopy().getVideoEnabled()) {
- currentCall.enableCamera(true);
- startVideoActivity(currentCall, 0);
- }
- else
- startIncallActivity();
+ FragmentsAvailable newFragment = (FragmentsAvailable) data.getExtras().getSerializable("FragmentToDisplay");
+ changeCurrentFragment(newFragment, null);
+ selectMenu(newFragment);
}
- return;
}
-
- Log.i("LinphoneActivity received an intent with data");
- // Ex: calling from native phone
- if (DialerActivity.instance() != null) {
- DialerActivity.instance().newOutgoingCall(intent);
- } else {
- Toast.makeText(this, getString(R.string.dialer_null_on_new_intent), Toast.LENGTH_LONG).show();
+ else if (requestCode == callActivity) {
+ if (LinphoneManager.getLc().getCallsNb() > 0) {
+ initInCallMenuLayout();
+ } else {
+ resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
+ }
}
+ super.onActivityResult(resultCode, requestCode, data);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (chatStorage != null) {
+ chatStorage.close();
+ }
+ chatStorage = new ChatStorage(this);
}
@Override
protected void onPause() {
super.onPause();
- if (isFinishing()) {
- //restore audio settings
- LinphoneManager.removeListener(this);
- LinphoneManager.stopProximitySensorForActivity(this);
- instance = null;
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the currently selected menu XML resource.
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.linphone_activity_menu, menu);
- menu.findItem(R.id.menu_settings).setVisible(useMenuSettings);
- menu.findItem(R.id.menu_about).setVisible(useMenuAbout);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
- if (lc == null)
- return true;
- // hide settings menu when in call
- // otherwise, exiting the 'setting' menu will cause exosip deletion/recreation...
- menu.findItem(R.id.menu_settings).setVisible(!lc.isIncall());
- return super.onPrepareOptionsMenu(menu);
+ chatStorage.close();
+ chatStorage = null;
}
-
+
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
- if (id == R.id.menu_settings) {
- startprefActivity();
- return true;
- }
- else if (id == R.id.menu_exit) {
- finish();
- stopService(new Intent(ACTION_MAIN)
- .setClass(this, LinphoneService.class));
- }
- else if (id == R.id.menu_about) {
- startActivity(new Intent(ACTION_MAIN)
- .setClass(this, AboutActivity.class));
- }
- else {
- Log.e("Unknown menu item [",item,"]");
- }
-
- return false;
- }
-
- void startprefActivity() {
- Intent intent = new Intent(ACTION_MAIN);
- intent.setClass(this, LinphonePreferencesActivity.class);
- startActivity(intent);
- }
-
-
- void showPreferenceErrorDialog(String message) {
- if (!useMenuSettings) {
- Toast.makeText(this, message, Toast.LENGTH_LONG);
- } else {
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setMessage(String.format(getString(R.string.config_error), message))
- .setCancelable(false)
- .setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- startprefActivity();
- }
- })
- .setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
-
- builder.create().show();
- }
- }
-
- public void onRegistrationStateChanged(RegistrationState state,
- String message) {
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
- if (FirstLoginActivity.instance != null) {
- FirstLoginActivity.instance.onRegistrationStateChanged(state);
+ Bundle extras = intent.getExtras();
+ if (extras != null && extras.getBoolean("GoToChat", false)) {
+ LinphoneService.instance().removeMessageNotification();
+ String sipUri = extras.getString("ChatContactSipUri");
+ displayChat(sipUri);
}
}
-
-
- /***** Check Account *******/
- private boolean checkDefined(SharedPreferences pref, int ... keys) {
- for (int key : keys) {
- String conf = pref.getString(getString(key), null);
- if (conf == null || "".equals(conf))
- return false;
- }
- return true;
- }
-
- private void onFirstLaunch() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- TextView lDialogTextView = new TextView(this);
- lDialogTextView.setAutoLinkMask(0x0f/*all*/);
- lDialogTextView.setPadding(10, 10, 10, 10);
-
- lDialogTextView.setText(Html.fromHtml(getString(R.string.first_launch_message)));
-
- builder.setCustomTitle(lDialogTextView)
- .setCancelable(false)
- .setPositiveButton(getString(R.string.cont), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- LinphoneManager.getInstance().initializePayloads();
- startprefActivity();
- checkAccount = false;
- }
- });
-
- builder.create().show();
- }
-
- private void onBadSettings(final SharedPreferences pref) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- TextView lDialogTextView = new TextView(this);
- lDialogTextView.setAutoLinkMask(0x0f/*all*/);
- lDialogTextView.setPadding(10, 10, 10, 10);
-
- lDialogTextView.setText(Html.fromHtml(getString(R.string.initial_config_error)));
-
- builder.setCustomTitle(lDialogTextView)
- .setCancelable(false)
- .setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- startprefActivity();
- checkAccount = false;
- }
- }).setNeutralButton(getString(R.string.no), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- checkAccount = false;
- }
- }).setNegativeButton(getString(R.string.never_remind), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- pref.edit().putBoolean(PREF_CHECK_CONFIG, true).commit();
- dialog.cancel();
- checkAccount = false;
- }
- });
-
- builder.create().show();
- }
-
- public void setAddressAndGoToDialer(String number, String name, Uri photo) {
- DialerActivity.instance().setContactAddress(number, name, photo);
- selectDialerTab();
- }
-
- private void selectDialerTab() {
- getTabHost().setCurrentTabByTag(DIALER_TAB);
- }
-
-
- private void startActivityInTab(String tag, Intent intent, int indicatorId, int drawableId) {
- Drawable tabDrawable = getResources().getDrawable(drawableId);
- TabSpec spec = getTabHost().newTabSpec(tag)
- .setIndicator(getString(indicatorId), tabDrawable)
- .setContent(intent);
- getTabHost().addTab(spec);
- }
-
-
- // Do not call if video activity already launched as it would cause a pause() of the launched one
- // and a race condition with capture surfaceview leading to a crash
- public void startVideoActivity(final LinphoneCall call, int delay) {
- if (VideoCallActivity.launched || call == null) {
- return;
- }
- mHandler.postDelayed(new Runnable() {
- public void run() {
- if (VideoCallActivity.launched) return;
- startOrientationSensor();
- //LinphoneManager.getInstance().enableCamera(call, true);
- startActivityForResult(new Intent().setClass(
- LinphoneActivity.this,
- VideoCallActivity.class),
- video_activity);
- // Avoid two consecutive runs to enter the previous block
- VideoCallActivity.launched = true;
- }
- }, delay);
- LinphoneManager.getInstance().routeAudioToSpeaker();
- }
-
- public synchronized void startIncallActivity() {
- if (IncallActivity.instance() != null && IncallActivity.instance().isActive()) {
- return;
- }
- mHandler.post(new Runnable() {
- public void run() {
- if (IncallActivity.active) return;
- Intent intent = new Intent().setClass(LinphoneActivity.this, IncallActivity.class);
- startActivityForResult(intent, incall_activity);
- }
- });
- }
-
- public void startIncomingCallActivity() {
- Intent intent = new Intent().setClass(this, IncomingCallActivity.class);
- startActivityForResult(intent, INCOMING_CALL_ACTIVITY);
- }
-
- /**
- * Register a sensor to track phoneOrientation changes
- */
- private synchronized void startOrientationSensor() {
- if (mOrientationHelper == null) {
- mOrientationHelper = new LocalOrientationEventListener(this);
- }
- mOrientationHelper.enable();
- }
-
- private int mAlwaysChangingPhoneAngle = -1;
- private class LocalOrientationEventListener extends OrientationEventListener {
- public LocalOrientationEventListener(Context context) {
- super(context);
- }
- @Override
- public void onOrientationChanged(final int o) {
- if (o == OrientationEventListener.ORIENTATION_UNKNOWN) return;
-
- int degrees=270;
- if (o < 45 || o >315) degrees=0;
- else if (o<135) degrees=90;
- else if (o<225) degrees=180;
-
- if (mAlwaysChangingPhoneAngle == degrees) return;
- mAlwaysChangingPhoneAngle = degrees;
-
- Log.d("Phone orientation changed to ", degrees);
- int rotation = (360 - degrees) % 360;
- LinphoneCore lc=LinphoneManager.getLcIfManagerNotDestroyedOrNull();
- if (lc!=null){
- lc.setDeviceRotation(rotation);
- LinphoneCall currentCall = lc.getCurrentCall();
- if (currentCall != null && currentCall.cameraEnabled() && currentCall.getCurrentParamsCopy().getVideoEnabled()) {
- lc.updateCall(currentCall, null);
- }
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && currentFragment == FragmentsAvailable.DIALER) {
+ if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) {
+ return true;
}
}
- }
-
- @Override
- public void onCallStateChanged(LinphoneCall call, State state,
- String message) {
- LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
- if (lc==null) {
- /* we are certainly exiting, ignore then.*/
- return;
- }
-
- if (state==State.IncomingReceived) {
- if (call.getCurrentParamsCopy().getVideoEnabled())
- startOrientationSensor();
- startIncomingCallActivity();
- }
- if (state == State.OutgoingInit) {
- if (call.getCurrentParamsCopy().getVideoEnabled()) {
- startOrientationSensor();
- startVideoActivity(call, 0);
- } else {
- startIncallActivity();
- }
- }
-
- if (state == LinphoneCall.State.StreamsRunning && Version.isVideoCapable() && !call.isInConference()) {
- // call.cameraEnabled() contains the wish of the user
- // set in LinphoneManager#onCallStateChanged(OutgoingInit||IncomingReceived)
- boolean videoEnabled = call.getCurrentParamsCopy().getVideoEnabled();
- if (videoEnabled) {
- finishActivity(incall_activity);
- startVideoActivity(call, 0);
- } else {
- finishActivity(video_activity);
- startIncallActivity();
- }
- }
-
- if (state == LinphoneCall.State.CallUpdatedByRemote && Version.isVideoCapable()) {
- if (VideoCallActivity.launched && !call.getCurrentParamsCopy().getVideoEnabled()) {
- finishActivity(video_activity);
- startIncallActivity();
- }
- }
-
- if (state == LinphoneCall.State.PausedByRemote) {
- finishActivity(video_activity);
- startIncallActivity();
- }
-
- if (state==State.Error){
- showToast(R.string.call_error, message);
- }
- if (state==State.Error || state==State.CallEnd) {
- finishActivity(INCOMING_CALL_ACTIVITY);
- if (lc.getCallsNb() == 0){
- exitIncallActivity();
- // Might be possible to optimize by disabling it before
- if (mOrientationHelper != null) mOrientationHelper.disable();
- }
- if (ConferenceDetailsActivity.active && lc.getConferenceSize() == 0) {
- finishActivity(conferenceDetailsActivity);
- }
- }
- }
-
- private void showToast(int id, String txt) {
- final String msg = String.format(getString(id), txt);
- mHandler.post(new Runnable() {
- public void run() {
- Toast.makeText(LinphoneActivity.this, msg, Toast.LENGTH_LONG).show();
- }
- });
- }
-
-
-
- private void exitIncallActivity() {
- setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE);
- }
-
-
- @Override
- protected void onResume() {
- super.onResume();
- LinphoneCall pendingCall = LinphoneManager.getInstance().getPendingIncomingCall();
- if (pendingCall != null) {
- startIncomingCallActivity();
- }
- }
-
- @Override
- public void goToDialer() {
- selectDialerTab();
- }
-
- public void startConferenceDetailsActivity() {
- startActivityForResult(new Intent().setClass(this, ConferenceDetailsActivity.class), conferenceDetailsActivity);
+ return super.onKeyDown(keyCode, event);
}
}
interface ContactPicked {
- void setAddressAndGoToDialer(String number, String name, Uri photo);
+ void setAddresGoToDialerAndCall(String number, String name, Uri photo);
void goToDialer();
-}
+}
\ No newline at end of file
diff --git a/src/org/linphone/LinphoneLauncherActivity.java b/src/org/linphone/LinphoneLauncherActivity.java
index 36537a443..17055dbd1 100644
--- a/src/org/linphone/LinphoneLauncherActivity.java
+++ b/src/org/linphone/LinphoneLauncherActivity.java
@@ -1,5 +1,5 @@
/*
-LinphoneLauncher.java
+LinphoneLauncherActivity.java
Copyright (C) 2011 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java
index 626108937..02b612a55 100644
--- a/src/org/linphone/LinphoneManager.java
+++ b/src/org/linphone/LinphoneManager.java
@@ -49,7 +49,6 @@ import java.util.TimerTask;
import org.linphone.LinphoneSimpleListener.LinphoneOnAudioChangedListener;
import org.linphone.LinphoneSimpleListener.LinphoneOnAudioChangedListener.AudioState;
-import org.linphone.LinphoneSimpleListener.LinphoneOnTextReceivedListener;
import org.linphone.LinphoneSimpleListener.LinphoneServiceListener;
import org.linphone.core.CallDirection;
import org.linphone.core.LinphoneAddress;
@@ -199,6 +198,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
private static void sRouteAudioToSpeakerHelperHelper(boolean speakerOn) {
getInstance().routeAudioToSpeakerHelperHelper(speakerOn);
}
+ @SuppressWarnings("deprecation")
private void routeAudioToSpeakerHelperHelper(boolean speakerOn) {
boolean different = isSpeakerOn() ^ speakerOn;
if (!different) {
@@ -295,8 +295,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
return getInstance().mLc;
}
-
-
+ @SuppressWarnings("deprecation")
public boolean isSpeakerOn() {
if (Hacks.needRoutingAPI() || sLPref.useAudioRoutingAPIHack()) {
return mAudioManager.getRouting(MODE_NORMAL) == ROUTE_SPEAKER;
@@ -895,11 +894,6 @@ public final class LinphoneManager implements LinphoneCoreListener {
private MediaPlayer mRingerPlayer;
private Vibrator mVibrator;
- private LinphoneOnTextReceivedListener textReceivedListener;
- public void setOnTextReceivedListener(LinphoneOnTextReceivedListener listener) {
- textReceivedListener = listener;
- }
-
public void displayWarning(LinphoneCore lc, String message) {}
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
public void byeReceived(LinphoneCore lc, String from) {}
@@ -907,10 +901,12 @@ public final class LinphoneManager implements LinphoneCoreListener {
public void show(LinphoneCore lc) {}
public void newSubscriptionRequest(LinphoneCore lc,LinphoneFriend lf,String url) {}
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
+
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,
LinphoneAddress from, String message) {
- if (textReceivedListener != null)
- textReceivedListener.onTextReceived(from, message);
+ for (LinphoneSimpleListener listener : getSimpleListeners(LinphoneActivity.class)) {
+ ((LinphoneActivity) listener).onMessageReceived(from, message);
+ }
}
@@ -1224,13 +1220,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
}
public static String extractIncomingRemoteName(Resources r, LinphoneAddress linphoneAddress) {
- if (!r.getBoolean(R.bool.show_full_remote_address_on_incoming_call))
- return extractADisplayName(r, linphoneAddress);
-
- if (linphoneAddress != null)
- return linphoneAddress.asStringUriOnly();
-
- return r.getString(R.string.unknown_incoming_call_name);
+ return extractADisplayName(r, linphoneAddress);
}
public void adjustVolume(int i) {
@@ -1394,6 +1384,9 @@ public final class LinphoneManager implements LinphoneCoreListener {
public void onRegistrationStateChanged(RegistrationState state,
String message) {
if (serviceListener != null) serviceListener.onRegistrationStateChanged(state, message);
+ for (LinphoneOnRegistrationStateChangedListener listener : getSimpleListeners(LinphoneActivity.class)) {
+ listener.onRegistrationStateChanged(state);
+ }
}
public void onRingerPlayerCreated(MediaPlayer mRingerPlayer) {
diff --git a/src/org/linphone/LinphonePreferencesActivity.java b/src/org/linphone/LinphonePreferencesActivity.java
index f15b19ded..2fa1dd601 100644
--- a/src/org/linphone/LinphonePreferencesActivity.java
+++ b/src/org/linphone/LinphonePreferencesActivity.java
@@ -1,6 +1,7 @@
+package org.linphone;
/*
LinphonePreferencesActivity.java
-Copyright (C) 2010 Belledonne Communications, Grenoble, France
+Copyright (C) 2012 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
@@ -15,856 +16,118 @@ 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.
- */
+*/
+import org.linphone.compatibility.Compatibility;
-package org.linphone;
-
-import static org.linphone.R.string.ec_calibrating;
-import static org.linphone.R.string.pref_codec_amr_key;
-import static org.linphone.R.string.pref_codec_amrwb_key;
-import static org.linphone.R.string.pref_codec_ilbc_key;
-import static org.linphone.R.string.pref_codec_speex16_key;
-import static org.linphone.R.string.pref_echo_cancellation_key;
-import static org.linphone.R.string.pref_echo_canceller_calibration_key;
-import static org.linphone.R.string.pref_echo_limiter_key;
-import static org.linphone.R.string.pref_media_encryption_key;
-import static org.linphone.R.string.pref_video_enable_key;
-
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.linphone.LinphoneManager.EcCalibrationListener;
-import org.linphone.LinphoneManager.LinphoneConfigException;
-import org.linphone.core.LinphoneCore;
-import org.linphone.core.LinphoneCore.EcCalibratorStatus;
-import org.linphone.core.LinphoneCore.MediaEncryption;
-import org.linphone.core.LinphoneCoreException;
-import org.linphone.core.Log;
-import org.linphone.mediastream.Version;
-import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
-import org.linphone.mediastream.video.capture.hwconf.Hacks;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.os.Bundle;
-import android.os.Handler;
-import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
-import android.preference.PreferenceCategory;
-import android.preference.PreferenceScreen;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.LayoutInflater;
+import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
-import de.timroes.axmlrpc.XMLRPCCallback;
-import de.timroes.axmlrpc.XMLRPCClient;
-import de.timroes.axmlrpc.XMLRPCException;
-import de.timroes.axmlrpc.XMLRPCServerException;
-public class LinphonePreferencesActivity extends PreferenceActivity implements EcCalibrationListener {
- private Handler mHandler = new Handler();
- private CheckBoxPreference ecCalibratePref;
- private CheckBoxPreference elPref;
- private CheckBoxPreference ecPref;
- private ListPreference mencPref;
- private int nbAccounts = 1;
-
- // Wizard fields
- private boolean usernameOk = false;
- private boolean passwordOk = false;
- private boolean emailOk = false;
- private AlertDialog wizardDialog;
- private Button createAccount;
- private TextView errorMessage;
- private PreferenceCategory accounts;
- private String username;
-
- private static final int ADD_SIP_ACCOUNT = 0x666;
- private static final int WIZARD_ID = 0x667;
- private static final int CONFIRM_ID = 0x668;
- private static final int ACCOUNTS_SETTINGS_ID = 0;
- private static final int ADD_ACCOUNT_SETTINGS_ID = 1;
- private static final int WIZARD_SETTINGS_ID = 2;
- private static final int CAMERA_SETTINGS_ID = 6;
-
- private SharedPreferences prefs() {
- return getPreferenceManager().getSharedPreferences();
- }
-
- private CheckBoxPreference findCheckbox(int key) {
- return (CheckBoxPreference) findPreference(getString(key));
- }
-
- private void detectAudioCodec(int id, String mime, int rate, boolean hide) {
- boolean enable = LinphoneService.isReady() && LinphoneManager.getLc().findPayloadType(mime, rate)!=null;
- Preference cb = findPreference(id);
- cb.setEnabled(enable);
- if (hide && !enable) {
- cb.setLayoutResource(R.layout.hidden);
- }
- }
-
- private void detectVideoCodec(int id, String mime) {
- findPreference(id).setEnabled(LinphoneManager.getInstance().detectVideoCodec(mime));
- }
-
- private void createDynamicAccountsPreferences() {
- accounts = (PreferenceCategory) getPreferenceScreen().getPreference(ACCOUNTS_SETTINGS_ID);
- accounts.removeAll();
-
- // Get already configured extra accounts
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- nbAccounts = prefs.getInt(getString(R.string.pref_extra_accounts), 0);
- for (int i = 0; i < nbAccounts; i++) {
- // For each, add menus to configure it
- addExtraAccountPreferencesButton(accounts, i, false);
- }
- }
-
- private void createAddAccountButton() {
- Preference addAccount = (Preference) getPreferenceScreen().getPreference(ADD_ACCOUNT_SETTINGS_ID);
- addAccount.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- addExtraAccountPreferencesButton(accounts, nbAccounts, true);
- Intent i = new Intent();
- i.putExtra("Account",nbAccounts);
- nbAccounts++;
- i.setClass(LinphonePreferencesActivity.this, LinphonePreferencesSIPAccountActivity.class);
- startActivityForResult(i, ADD_SIP_ACCOUNT);
- return true;
- }
- });
- }
-
- public int getNbAccountsExtra() {
- return nbAccounts;
- }
-
- private void addExtraAccountPreferencesButton(PreferenceCategory parent, final int n, boolean isNewAccount) {
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- if (isNewAccount) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(getString(R.string.pref_extra_accounts), n+1);
- editor.commit();
- }
-
- Preference me = new Preference(LinphonePreferencesActivity.this);
- String keyUsername = getString(R.string.pref_username_key);
- String keyDomain = getString(R.string.pref_domain_key);
- if (n > 0) {
- keyUsername += n + "";
- keyDomain += n + "";
- }
- if (prefs.getString(keyUsername, null) == null) {
- me.setTitle(getString(R.string.pref_sipaccount));
- } else {
- me.setTitle(prefs.getString(keyUsername, "") + "@" + prefs.getString(keyDomain, ""));
- }
-
- me.setOnPreferenceClickListener(new OnPreferenceClickListener()
- {
- public boolean onPreferenceClick(Preference preference) {
- Intent i = new Intent();
- i.putExtra("Account", n);
- i.setClass(LinphonePreferencesActivity.this, LinphonePreferencesSIPAccountActivity.class);
- startActivityForResult(i, ADD_SIP_ACCOUNT);
- return false;
- }
- });
- parent.addPreference(me);
- }
-
- private void fillLinphoneAccount(int i, String username, String password, boolean createdByWizard) {
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- SharedPreferences.Editor editor = prefs.edit();
-
- editor.putString(getString(R.string.pref_username_key) + i, username);
- editor.putString(getString(R.string.pref_passwd_key) + i, password);
- editor.putString(getString(R.string.pref_domain_key) + i, "sip.linphone.org");
- editor.putString(getString(R.string.pref_proxy_key) + i, "");
- editor.putBoolean(getString(R.string.pref_wizard_key) + i, createdByWizard);
- editor.putBoolean(getString(R.string.pref_activated_key) + i, false);
- editor.putBoolean(getString(R.string.pref_enable_outbound_proxy_key) + i, false);
-
- editor.commit();
- }
-
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (requestCode == ADD_SIP_ACCOUNT) {
- //Verify if last created account is filled
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- int n = prefs.getInt(getString(R.string.pref_extra_accounts), 1);
- String keyUsername = getString(R.string.pref_username_key) + (n-1 == 0 ? "" : Integer.toString(n-1));
-
- if (prefs.getString(keyUsername, "").equals("")) {
- //If not, we suppress it to not display a blank field
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(getString(R.string.pref_extra_accounts), n-1);
- editor.commit();
- }
-
- createDynamicAccountsPreferences();
- }
- }
-
- private void addWizardPreferenceButton() {
- Preference wizard = (Preference) getPreferenceScreen().getPreference(WIZARD_SETTINGS_ID);
- wizard.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- showDialog(WIZARD_ID);
- return true;
- }
- });
- }
-
- protected Dialog onCreateDialog (int id) {
- if (id == WIZARD_ID) {
- AlertDialog.Builder builder = new AlertDialog.Builder(LinphonePreferencesActivity.this);
- LayoutInflater inflater = LayoutInflater.from(LinphonePreferencesActivity.this);
- View v = inflater.inflate(R.layout.wizard, null);
- builder.setView(v);
-
- final EditText username = (EditText) v.findViewById(R.id.wizardUsername);
- ImageView usernameOkIV = (ImageView) v.findViewById(R.id.wizardUsernameOk);
- addXMLRPCUsernameHandler(username, usernameOkIV);
-
- final EditText password = (EditText) v.findViewById(R.id.wizardPassword);
- EditText passwordConfirm = (EditText) v.findViewById(R.id.wizardPasswordConfirm);
- ImageView passwordOkIV = (ImageView) v.findViewById(R.id.wizardPasswordOk);
- addXMLRPCPasswordHandler(password, passwordConfirm, passwordOkIV);
-
- final EditText email = (EditText) v.findViewById(R.id.wizardEmail);
- ImageView emailOkIV = (ImageView) v.findViewById(R.id.wizardEmailOk);
- addXMLRPCEmailHandler(email, emailOkIV);
-
- errorMessage = (TextView) v.findViewById(R.id.wizardErrorMessage);
-
- Button cancel = (Button) v.findViewById(R.id.wizardCancel);
- cancel.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- wizardDialog.dismiss();
- }
- });
-
- createAccount = (Button) v.findViewById(R.id.wizardCreateAccount);
- createAccount.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- createAccount(username.getText().toString(), password.getText().toString(), email.getText().toString(), false);
- }
- });
- createAccount.setEnabled(false);
-
- builder.setTitle(getString(R.string.wizard_title));
- wizardDialog = builder.create();
- return wizardDialog;
- }
- else if (id == CONFIRM_ID) {
- AlertDialog.Builder builder = new AlertDialog.Builder(LinphonePreferencesActivity.this);
- builder.setTitle(R.string.wizard_confirmation);
-
- final LayoutInflater inflater = LayoutInflater.from(LinphonePreferencesActivity.this);
- View v = inflater.inflate(R.layout.wizard_confirm, null);
- builder.setView(v);
-
- Button check = (Button) v.findViewById(R.id.wizardCheckAccount);
- check.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- wizardDialog.dismiss();
- if (isAccountVerified(username)) {
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(getString(R.string.pref_activated_key) + (nbAccounts - 1), true);
- editor.commit();
- } else {
- showDialog(CONFIRM_ID);
- }
- }
- });
-
- Button cancel = (Button) v.findViewById(R.id.wizardCancel);
- cancel.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- wizardDialog.dismiss();
- }
- });
-
- wizardDialog = builder.create();
- return wizardDialog;
- }
- return null;
- }
-
- private boolean isUsernameCorrect(String username) {
- return username.matches("^[a-zA-Z]+[a-zA-Z0-9.\\-_]{2,}$");
- }
-
- static boolean isAccountVerified(String username) {
- try {
- XMLRPCClient client = new XMLRPCClient(new URL("https://www.linphone.org/wizard.php"));
- Object resultO = client.call("check_account_validated", "sip:" + username + "@sip.linphone.org");
- Integer result = Integer.parseInt(resultO.toString());
-
- return result == 1;
- } catch(Exception ex) {
-
- }
- return false;
- }
-
- private void isUsernameRegistred(String username, final ImageView icon) {
- final Runnable runNotReachable = new Runnable() {
- public void run() {
- errorMessage.setText(R.string.wizard_server_unavailable);
- usernameOk = false;
- icon.setImageResource(R.drawable.notok);
- createAccount.setEnabled(usernameOk && passwordOk && emailOk);
- }
- };
-
- try {
- XMLRPCClient client = new XMLRPCClient(new URL("https://www.linphone.org/wizard.php"));
-
- XMLRPCCallback listener = new XMLRPCCallback() {
- Runnable runNotOk = new Runnable() {
- public void run() {
- errorMessage.setText(R.string.wizard_username_unavailable);
- usernameOk = false;
- icon.setImageResource(R.drawable.notok);
- createAccount.setEnabled(usernameOk && passwordOk && emailOk);
- }
- };
-
- Runnable runOk = new Runnable() {
- public void run() {
- errorMessage.setText("");
- icon.setImageResource(R.drawable.ok);
- usernameOk = true;
- createAccount.setEnabled(usernameOk && passwordOk && emailOk);
- }
- };
-
- public void onResponse(long id, Object result) {
- int answer = (Integer) result;
- if (answer != 0) {
- runOnUiThread(runNotOk);
- }
- else {
- runOnUiThread(runOk);
- }
- }
-
- public void onError(long id, XMLRPCException error) {
- runOnUiThread(runNotReachable);
- }
-
- public void onServerError(long id, XMLRPCServerException error) {
- runOnUiThread(runNotReachable);
- }
- };
-
- client.callAsync(listener, "check_account", username);
- }
- catch(Exception ex) {
- runOnUiThread(runNotReachable);
- }
- }
-
- private boolean isEmailCorrect(String email) {
- return email.matches("^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\\.-][a-z0-9]+)*)+\\.[a-z]{2,}$");
- }
-
- private boolean isPasswordCorrect(String password) {
- return password.length() >= 6;
- }
-
- private void createAccount(final String username, final String password, String email, boolean suscribe) {
- final Runnable runNotReachable = new Runnable() {
- public void run() {
- errorMessage.setText(R.string.wizard_server_unavailable);
- }
- };
-
- try {
- XMLRPCClient client = new XMLRPCClient(new URL("https://www.linphone.org/wizard.php"));
-
- XMLRPCCallback listener = new XMLRPCCallback() {
- Runnable runNotOk = new Runnable() {
- public void run() {
- errorMessage.setText(R.string.wizard_failed);
- }
- };
-
- Runnable runOk = new Runnable() {
- public void run() {
- addExtraAccountPreferencesButton(accounts, nbAccounts, true);
- LinphonePreferencesActivity.this.username = username;
- fillLinphoneAccount(nbAccounts, username, password, true);
- nbAccounts++;
- createDynamicAccountsPreferences();
- wizardDialog.dismiss();
-
- showDialog(CONFIRM_ID);
- }
- };
-
- public void onResponse(long id, Object result) {
- int answer = (Integer) result;
- if (answer != 0) {
- runOnUiThread(runNotOk);
- } else {
- runOnUiThread(runOk);
- }
- }
-
- public void onError(long id, XMLRPCException error) {
- runOnUiThread(runNotReachable);
- }
-
- public void onServerError(long id, XMLRPCServerException error) {
- runOnUiThread(runNotReachable);
- }
- };
-
- client.callAsync(listener, "create_account", username, password, email, suscribe ? 1 : 0);
- }
- catch(Exception ex) {
- runOnUiThread(runNotReachable);
- }
- }
-
- private void addXMLRPCUsernameHandler(final EditText field, final ImageView icon) {
- field.addTextChangedListener(new TextWatcher() {
- public void afterTextChanged(Editable arg0) {
-
- }
-
- public void beforeTextChanged(CharSequence arg0, int arg1,
- int arg2, int arg3) {
-
- }
-
- public void onTextChanged(CharSequence arg0, int arg1, int arg2,
- int arg3)
- {
- usernameOk = false;
- if (isUsernameCorrect(field.getText().toString()))
- {
- isUsernameRegistred(field.getText().toString(), icon);
- }
- else {
- errorMessage.setText(R.string.wizard_username_incorrect);
- icon.setImageResource(R.drawable.notok);
- }
- }
- });
- }
-
- private void addXMLRPCEmailHandler(final EditText field, final ImageView icon) {
- field.addTextChangedListener(new TextWatcher() {
- public void afterTextChanged(Editable arg0) {
-
- }
-
- public void beforeTextChanged(CharSequence arg0, int arg1,
- int arg2, int arg3) {
-
- }
-
- public void onTextChanged(CharSequence arg0, int arg1, int arg2,
- int arg3)
- {
- emailOk = false;
- if (isEmailCorrect(field.getText().toString())) {
- icon.setImageResource(R.drawable.ok);
- emailOk = true;
- errorMessage.setText("");
- }
- else {
- errorMessage.setText(R.string.wizard_email_incorrect);
- icon.setImageResource(R.drawable.notok);
- }
- createAccount.setEnabled(usernameOk && passwordOk && emailOk);
- }
- });
- }
-
- private void addXMLRPCPasswordHandler(final EditText field1, final EditText field2, final ImageView icon) {
- TextWatcher passwordListener = new TextWatcher() {
- public void afterTextChanged(Editable arg0) {
-
- }
-
- public void beforeTextChanged(CharSequence arg0, int arg1,
- int arg2, int arg3) {
-
- }
-
- public void onTextChanged(CharSequence arg0, int arg1, int arg2,
- int arg3)
- {
- passwordOk = false;
- if (isPasswordCorrect(field1.getText().toString()) && field1.getText().toString().equals(field2.getText().toString())) {
- passwordOk = true;
- icon.setImageResource(R.drawable.ok);
- errorMessage.setText("");
- }
- else {
- if (isPasswordCorrect(field1.getText().toString())) {
- errorMessage.setText(R.string.wizard_passwords_unmatched);
- }
- else {
- errorMessage.setText(R.string.wizard_password_incorrect);
- }
- icon.setImageResource(R.drawable.notok);
- }
- createAccount.setEnabled(usernameOk && passwordOk && emailOk);
- }
- };
-
- field1.addTextChangedListener(passwordListener);
- field2.addTextChangedListener(passwordListener);
- }
-
- private void verifiyAccountsActivated() {
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- for (int i = 0; i < nbAccounts; i++) {
- String key = (i == 0 ? "" : Integer.toString(i));
- boolean createdByWizard = prefs.getBoolean(getString(R.string.pref_wizard_key) + key, false);
- boolean activated = prefs.getBoolean(getString(R.string.pref_activated_key) + key, true);
- if (createdByWizard && !activated) {
- //Check if account has been activated since
- activated = isAccountVerified(prefs.getString(getString(R.string.pref_username_key) + key, ""));
- if (activated) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(getString(R.string.pref_activated_key) + key, true);
- editor.commit();
- } else {
- showDialog(CONFIRM_ID);
- }
- }
- }
- }
+/**
+ * @author Sylvain Berfini
+ */
+public class LinphonePreferencesActivity extends PreferenceActivity implements OnClickListener {
+ private ImageView history, contacts, dialer, settings, chat;
+ private TextView missedCalls;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.preferences);
-
- if (!getResources().getBoolean(R.bool.hide_accounts)) {
- createDynamicAccountsPreferences();
-
- // Accounts have to be displayed to show add account button
- if (getResources().getBoolean(R.bool.hide_add_account_button)) {
- Preference addAccount = (Preference) getPreferenceScreen().getPreference(ADD_ACCOUNT_SETTINGS_ID);
- addAccount.setLayoutResource(R.layout.hidden);
- } else {
- createAddAccountButton();
- }
- } else {
- // Hide add account button if accounts are hidden
- Preference addAccount = (Preference) getPreferenceScreen().getPreference(ADD_ACCOUNT_SETTINGS_ID);
- addAccount.setLayoutResource(R.layout.hidden);
-
- // Hide category
- PreferenceCategory accounts = (PreferenceCategory) getPreferenceScreen().getPreference(ACCOUNTS_SETTINGS_ID);
- accounts.removeAll();
- accounts.setLayoutResource(R.layout.hidden);
- }
+ // Hack to allow custom view in preferences, in this case the bottom menu
+ setContentView(R.layout.settings);
- if (getResources().getBoolean(R.bool.hide_wizard)) {
- Preference wizard = (Preference) getPreferenceScreen().getPreference(WIZARD_SETTINGS_ID);
- wizard.setLayoutResource(R.layout.hidden);
- } else {
- addWizardPreferenceButton();
- verifiyAccountsActivated();
- }
+ initButtons();
- addTransportChecboxesListener();
-
- ecCalibratePref = (CheckBoxPreference) findPreference(pref_echo_canceller_calibration_key);
- ecCalibratePref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- startEcCalibration();
- return false;
- }
- });
- ecPref = (CheckBoxPreference) findPreference(pref_echo_cancellation_key);
- elPref = (CheckBoxPreference) findPreference(pref_echo_limiter_key);
- mencPref = (ListPreference) findPreference(pref_media_encryption_key);
-
- boolean fastCpu = Version.isArmv7();
- if (fastCpu) {
- detectAudioCodec(pref_codec_ilbc_key, "iLBC", 8000, false);
- findPreference(pref_codec_speex16_key).setEnabled(true);
- //findPreference(pref_codec_speex32_key)).setEnabled(enableIlbc);
- }
- findPreference(pref_echo_limiter_key).setEnabled(true);
-
- initializeMediaEncryptionPreferences();
+ int missedCalls = LinphoneManager.getLc().getMissedCallsCount();
+ displayMissedCalls(missedCalls);
+ }
- detectAudioCodec(pref_codec_amr_key,"AMR", 8000, false);
- detectAudioCodec(pref_codec_amrwb_key,"AMR-WB", 16000, false);
- //detectAudioCodec(R.string.pref_codec_silk8_key,"SILK",8000, true);
- //detectAudioCodec(R.string.pref_codec_silk12_key,"SILK",12000, true);
- detectAudioCodec(R.string.pref_codec_silk16_key,"SILK",16000, true);
- detectAudioCodec(R.string.pref_codec_silk24_key,"SILK",24000, true);
- detectAudioCodec(R.string.pref_codec_g729_key,"G729",8000, true);
+ private void initButtons() {
+ history = (ImageView) findViewById(R.id.history);
+ history.setOnClickListener(this);
+ contacts = (ImageView) findViewById(R.id.contacts);
+ contacts.setOnClickListener(this);
+ dialer = (ImageView) findViewById(R.id.dialer);
+ dialer.setOnClickListener(this);
+ dialer.setSelected(true);
+ settings = (ImageView) findViewById(R.id.settings);
+ settings.setOnClickListener(this);
+ chat = (ImageView) findViewById(R.id.chat);
+ chat.setOnClickListener(this);
+ missedCalls = (TextView) findViewById(R.id.missedCalls);
- // No video
- if (!Version.isVideoCapable()) {
- uncheckAndDisableCheckbox(pref_video_enable_key);
- } else if (!AndroidCameraConfiguration.hasFrontCamera()) {
- uncheckDisableAndHideCheckbox(R.string.pref_video_use_front_camera_key);
- }
-
- if (prefs().getBoolean(LinphoneActivity.PREF_FIRST_LAUNCH,true)) {
- doOnFirstLaunch();
- }
- if (Hacks.hasBuiltInEchoCanceller()) {
- uncheckDisableAndHideCheckbox(R.string.pref_echo_limiter_key);
- uncheckDisableAndHideCheckbox(R.string.pref_echo_cancellation_key);
- uncheckDisableAndHideCheckbox(R.string.pref_echo_canceller_calibration_key);
- }
-
-
- detectVideoCodec(R.string.pref_video_codec_h264_key, "H264");
- if (!Version.hasNeon())
- {
- // Android without neon doesn't support H264
- findPreference(R.string.pref_video_codec_h264_key).setEnabled(false);
- findPreference(R.string.pref_video_codec_h264_key).setDefaultValue(false);
- }
-
- addEchoPrefsListener();
-
- if (Hacks.needSoftvolume()) checkAndDisableCheckbox(R.string.pref_audio_soft_volume_key);
-
- if (!LinphoneManager.getLc().isTunnelAvailable()){
- hidePreferenceCategory(R.string.pref_tunnel_key);
- }
-
- if (getResources().getBoolean(R.bool.hide_camera_settings)) {
- PreferenceScreen screen = getPreferenceScreen();
- PreferenceCategory videoSettings = (PreferenceCategory) screen.getPreference(CAMERA_SETTINGS_ID);
- videoSettings.removeAll();
- videoSettings.setLayoutResource(R.layout.hidden);
-
- CheckBoxPreference enableVideo = (CheckBoxPreference) findPreference(R.string.pref_video_enable_key);
- enableVideo.setLayoutResource(R.layout.hidden);
- }
+ history.setSelected(false);
+ contacts.setSelected(false);
+ dialer.setSelected(false);
+ settings.setSelected(true);
+ chat.setSelected(false);
}
-
- private void hidePreferenceCategory(int key) {
- PreferenceCategory p = (PreferenceCategory) findPreference(key);
- p.removeAll();
- p.setLayoutResource(R.layout.hidden);
- }
-
- private void doOnFirstLaunch() {
- manageCheckbox(R.string.pref_echo_limiter_key, !Hacks.hasBuiltInEchoCanceller(), true, false);
- prefs().edit().putBoolean(LinphoneActivity.PREF_FIRST_LAUNCH, false).commit();
- }
-
- private void initializeMediaEncryptionPreferences() {
- LinphoneCore lc=LinphoneManager.getLc();
- boolean hasZrtp=lc.mediaEncryptionSupported(MediaEncryption.ZRTP);
- boolean hasSrtp=lc.mediaEncryptionSupported(MediaEncryption.SRTP);
- if (!hasSrtp && !hasZrtp){
- mencPref.setEnabled(false);
- }else{
- List mencEntries=new ArrayList();
- List mencEntryValues=new ArrayList();
- mencEntries.add(getString(R.string.media_encryption_none));
- mencEntryValues.add(getString(R.string.pref_media_encryption_key_none));
- if (hasSrtp){
- mencEntries.add(getString(R.string.media_encryption_srtp));
- mencEntryValues.add(getString(R.string.pref_media_encryption_key_srtp));
- }
- if (hasZrtp){
- mencEntries.add(getString(R.string.media_encryption_zrtp));
- mencEntryValues.add(getString(R.string.pref_media_encryption_key_zrtp));
- }
- CharSequence[] contents=new CharSequence[mencEntries.size()];
- mencEntries.toArray(contents);
- mencPref.setEntries(contents);
- contents=new CharSequence[mencEntryValues.size()];
- mencEntryValues.toArray(contents);
- mencPref.setEntryValues(contents);
- mencPref.setDefaultValue(getString(R.string.media_encryption_none));
- //mencPref.setValueIndex(mencPref.findIndexOfValue(getString(R.string.media_encryption_none)));
- }
- }
-
- private void addEchoPrefsListener(){
- OnPreferenceChangeListener ec_listener=new OnPreferenceChangeListener(){
- public boolean onPreferenceChange(Preference arg0, Object newValue) {
- Boolean val=(Boolean)newValue;
- if (val){
- elPref.setChecked(!val);
- }
- return true;
- }
- };
- OnPreferenceChangeListener el_listener=new OnPreferenceChangeListener(){
- public boolean onPreferenceChange(Preference arg0, Object newValue) {
- Boolean val=(Boolean)newValue;
- if (val){
- ecPref.setChecked(!val);
- }
- return true;
- }
- };
- ecPref.setOnPreferenceChangeListener(ec_listener);
- elPref.setOnPreferenceChangeListener(el_listener);
- }
-
- private void addTransportChecboxesListener() {
-
- final List checkboxes = Arrays.asList(
- findCheckbox(R.string.pref_transport_udp_key)
- ,findCheckbox(R.string.pref_transport_tcp_key)
- ,findCheckbox(R.string.pref_transport_tls_key)
- );
-
-
- OnPreferenceChangeListener changedListener = new OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if ((Boolean) newValue) {
- for (CheckBoxPreference p : checkboxes) {
- if (p == preference) continue;
- p.setChecked(false);
- }
- return true;
- } else {
- for (CheckBoxPreference p : checkboxes) {
- if (p == preference) continue;
- if (p.isChecked()) return true;
- }
- return false;
- }
- }
- };
-
- OnPreferenceClickListener clickListener = new OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- // Forbid no protocol selection
-
- if (((CheckBoxPreference) preference).isChecked()) {
- // Trying to unckeck
- for (CheckBoxPreference p : checkboxes) {
- if (p == preference) continue;
- if (p.isChecked()) return false;
- }
- /*Toast.makeText(LinphonePreferencesActivity.this,
- getString(R.string.at_least_a_protocol),
- Toast.LENGTH_SHORT).show();*/
- return true;
- }
- return false;
- }
- };
-
- for (CheckBoxPreference c : checkboxes) {
- c.setOnPreferenceChangeListener(changedListener);
- c.setOnPreferenceClickListener(clickListener);
- }
- }
-
- private synchronized void startEcCalibration() {
- try {
- LinphoneManager.getInstance().startEcCalibration(this);
-
- ecCalibratePref.setSummary(ec_calibrating);
- ecCalibratePref.getEditor().putBoolean(getString(pref_echo_canceller_calibration_key), false).commit();
- } catch (LinphoneCoreException e) {
- Log.w(e, "Cannot calibrate EC");
- }
- }
-
- public void onEcCalibrationStatus(final EcCalibratorStatus status, final int delayMs) {
-
- mHandler.post(new Runnable() {
- public void run() {
- if (status == EcCalibratorStatus.Done) {
- ecCalibratePref.setSummary(String.format(getString(R.string.ec_calibrated), delayMs));
- ecCalibratePref.setChecked(true);
-
- } else if (status == EcCalibratorStatus.Failed) {
- ecCalibratePref.setSummary(R.string.failed);
- ecCalibratePref.setChecked(false);
- elPref.setChecked(true);
- ecPref.setChecked(false);
- }
- }
- });
- }
-
- private void uncheckDisableAndHideCheckbox(int key) {
- manageCheckbox(key, false, false, true);
- }
-
- private void uncheckAndDisableCheckbox(int key) {
- manageCheckbox(key, false, false, false);
- }
- private void checkAndDisableCheckbox(int key) {
- manageCheckbox(key, true, false, false);
- }
- private void manageCheckbox(int key, boolean value, boolean enabled, boolean hidden) {
- CheckBoxPreference box = (CheckBoxPreference) findPreference(key);
- box.setEnabled(enabled);
- box.setChecked(value);
- writeBoolean(key, value);
- if (hidden) box.setLayoutResource(R.layout.hidden);
- }
-
- private Preference findPreference(int key) {
- return getPreferenceManager().findPreference(getString(key));
- }
-
- private void writeBoolean(int key, boolean value) {
- prefs().edit().putBoolean(getString(key), value).commit();
- }
-
+
@Override
- protected void onPause() {
- super.onPause();
-
- if (!isFinishing()) return;
-
- LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
+ public void onClick(View v) {
+ int id = v.getId();
- if (lc != null && (lc.isInComingInvitePending() || lc.isIncall())) {
- Log.w("Call in progress => settings not applied");
- return;
+ FragmentsAvailable newFragment = FragmentsAvailable.SETTINGS;
+ if (id == R.id.history) {
+ newFragment = FragmentsAvailable.HISTORY;
}
-
- try {
- LinphoneManager.getInstance().initFromConf();
- lc.setVideoPolicy(LinphoneManager.getInstance().isAutoInitiateVideoCalls(), LinphoneManager.getInstance().isAutoAcceptCamera());
- } catch (LinphoneException e) {
- if (! (e instanceof LinphoneConfigException)) {
- Log.e(e, "Cannot update config");
- return;
- }
-
- LinphoneActivity.instance().showPreferenceErrorDialog(e.getMessage());
+ else if (id == R.id.contacts) {
+ newFragment = FragmentsAvailable.CONTACTS;
+ }
+ else if (id == R.id.dialer) {
+ newFragment = FragmentsAvailable.DIALER;
+ }
+ else if (id == R.id.chat) {
+ newFragment = FragmentsAvailable.CHATLIST;
+ }
+
+ if (newFragment != FragmentsAvailable.SETTINGS) {
+ Intent intent = new Intent();
+ intent.putExtra("FragmentToDisplay", newFragment);
+ setResult(RESULT_FIRST_USER, intent);
+ finishWithCustomAnimation(newFragment);
}
}
-
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (resultCode == RESULT_FIRST_USER) {
+ // If we were on a LinphonePreferences sub activity, and we came back because of a change of tab, we propagate the event
+ setResult(RESULT_FIRST_USER, data);
+ finish();
+ }
+ }
+
+ private void displayMissedCalls(final int missedCallsCount) {
+ if (missedCallsCount > 0) {
+ missedCalls.setText(missedCallsCount + "");
+ missedCalls.setVisibility(View.VISIBLE);
+ } else {
+ missedCalls.setVisibility(View.GONE);
+ }
+ }
+
+ private void finishWithCustomAnimation(FragmentsAvailable newFragment) {
+ finish();
+ if (FragmentsAvailable.SETTINGS.isRightOf(newFragment)) {
+ Compatibility.overridePendingTransition(this, R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right);
+ } else {
+ Compatibility.overridePendingTransition(this, R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left);
+ }
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ finishWithCustomAnimation(LinphoneActivity.instance().getCurrentFragment());
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
}
diff --git a/src/org/linphone/LinphoneService.java b/src/org/linphone/LinphoneService.java
index 594baf803..9d32be753 100644
--- a/src/org/linphone/LinphoneService.java
+++ b/src/org/linphone/LinphoneService.java
@@ -98,11 +98,13 @@ public final class LinphoneService extends Service implements LinphoneServiceLis
private final static int NOTIF_ID=1;
private final static int INCALL_NOTIF_ID=2;
- private final static int CUSTOM_NOTIF_ID=3;
+ private final static int MESSAGE_NOTIF_ID=3;
+ private final static int CUSTOM_NOTIF_ID=4;
private Notification mNotif;
private Notification mIncallNotif;
private Notification mMsgNotif;
+ private int mMsgNotifCount;
private PendingIntent mNotifContentIntent;
private String mNotificationTitle;
@@ -141,7 +143,7 @@ public final class LinphoneService extends Service implements LinphoneServiceLis
mNotif.flags |= Notification.FLAG_ONGOING_EVENT;
Intent notifIntent = new Intent(this, incomingReceivedActivity);
- mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, 0);
+ mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT);
mNotif.setLatestEventInfo(this, mNotificationTitle,"", mNotifContentIntent);
LinphoneManager.createAndStart(this, this);
@@ -254,6 +256,47 @@ public final class LinphoneService extends Service implements LinphoneServiceLis
notifyWrapper(CUSTOM_NOTIF_ID, mMsgNotif);
}
+
+ public void displayMessageNotification(String fromSipUri, String fromName, String message) {
+ Intent notifIntent = new Intent(this, LinphoneActivity.class);
+ notifIntent.putExtra("GoToChat", true);
+ notifIntent.putExtra("ChatContactSipUri", fromSipUri);
+
+ PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ if (fromName == null) {
+ fromName = fromSipUri;
+ }
+
+ if (mMsgNotif == null) {
+ mMsgNotifCount = 1;
+ mMsgNotif = new Notification();
+
+ mMsgNotif.icon = R.drawable.chat_icon_over;
+ mMsgNotif.iconLevel = 0;
+ mMsgNotif.when = System.currentTimeMillis();
+ mMsgNotif.flags &= Notification.FLAG_ONGOING_EVENT;
+
+ mMsgNotif.defaults |= Notification.DEFAULT_VIBRATE;
+ mMsgNotif.defaults |= Notification.DEFAULT_SOUND;
+ mMsgNotif.defaults |= Notification.DEFAULT_LIGHTS;
+
+ String title = "New message from %s :".replace("%s", fromName);
+ mMsgNotif.setLatestEventInfo(this, title, message, notifContentIntent);
+ } else {
+ mMsgNotifCount++;
+ mMsgNotif.when = System.currentTimeMillis();
+
+ String title = mMsgNotifCount + " new messages from %s".replace("%s", fromName);
+ mMsgNotif.setLatestEventInfo(this, title, "", notifContentIntent);
+ }
+
+ notifyWrapper(MESSAGE_NOTIF_ID, mMsgNotif);
+ }
+
+ public void removeMessageNotification() {
+ mNM.cancel(MESSAGE_NOTIF_ID);
+ }
private static final Class>[] mSetFgSign = new Class[] {boolean.class};
private static final Class>[] mStartFgSign = new Class[] {
@@ -399,17 +442,18 @@ public final class LinphoneService extends Service implements LinphoneServiceLis
// Make sure our notification is gone.
stopForegroundCompat(NOTIF_ID);
mNM.cancel(INCALL_NOTIF_ID);
+ mNM.cancel(MESSAGE_NOTIF_ID);
mWifiLock.release();
super.onDestroy();
}
private static final LinphoneGuiListener guiListener() {
- return DialerActivity.instance();
+ return null;
}
private static final LinphoneOnCallStateChangedListener incallListener() {
- return IncallActivity.instance();
+ return InCallActivity.instance();
}
@@ -455,14 +499,13 @@ public final class LinphoneService extends Service implements LinphoneServiceLis
sendNotification(IC_LEVEL_OFFLINE, R.string.notification_register_failure);
}
- if (state == RegistrationState.RegistrationOk || state == RegistrationState.RegistrationFailed) {
- mHandler.post(new Runnable() {
- public void run() {
- if (LinphoneActivity.isInstanciated())
- LinphoneActivity.instance().onRegistrationStateChanged(state, message);
+ mHandler.post(new Runnable() {
+ public void run() {
+ if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().onRegistrationStateChanged(state, message);
}
- });
- }
+ }
+ });
}
public void setActivityToLaunchOnIncomingReceived(Class extends Activity> activity) {
diff --git a/src/org/linphone/LinphoneSimpleListener.java b/src/org/linphone/LinphoneSimpleListener.java
index 87d27980c..75106a99c 100644
--- a/src/org/linphone/LinphoneSimpleListener.java
+++ b/src/org/linphone/LinphoneSimpleListener.java
@@ -59,8 +59,11 @@ public interface LinphoneSimpleListener {
void onAudioStateChanged(AudioState state);
}
- public static interface LinphoneOnTextReceivedListener extends LinphoneSimpleListener {
- void onTextReceived(LinphoneAddress from, String message);
+ public static interface LinphoneOnMessageReceivedListener extends LinphoneSimpleListener {
+ void onMessageReceived(LinphoneAddress from, String message);
}
+ public static interface LinphoneOnRegistrationStateChangedListener extends LinphoneSimpleListener {
+ void onRegistrationStateChanged(RegistrationState state);
+ }
}
diff --git a/src/org/linphone/LinphoneUtils.java b/src/org/linphone/LinphoneUtils.java
index 9722e2400..7552972fb 100644
--- a/src/org/linphone/LinphoneUtils.java
+++ b/src/org/linphone/LinphoneUtils.java
@@ -28,15 +28,13 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
-import java.util.Set;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCore;
import org.linphone.core.Log;
-import org.linphone.core.LinphoneCall.State;
import org.linphone.mediastream.Version;
import org.linphone.mediastream.video.capture.hwconf.Hacks;
@@ -64,6 +62,20 @@ public final class LinphoneUtils {
private static boolean preventVolumeBarToDisplay = false;
+ public static boolean isSipAddress(String numberOrAddress) {
+ return numberOrAddress != null && numberOrAddress.matches("^(sip:)?[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\\.-][a-z0-9]+)*)+\\.[a-z]{2,}$");
+ }
+
+ public static String getUsernameFromAddress(String address) {
+ if (address.contains("sip:"))
+ address = address.replace("sip:", "");
+
+ if (address.contains("@"))
+ address = address.split("@")[0];
+
+ return address;
+ }
+
public static boolean onKeyBackGoHome(Activity activity, int keyCode, KeyEvent event) {
if (!(keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)) {
return false; // continue
@@ -77,7 +89,7 @@ public final class LinphoneUtils {
public static boolean onKeyVolumeAdjust(int keyCode) {
if (!((keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
- && (Hacks.needSoftvolume())|| Build.VERSION.SDK_INT>=15)) {
+ && (Hacks.needSoftvolume())|| Build.VERSION.SDK_INT >= 15)) {
return false; // continue
}
diff --git a/src/org/linphone/PreferencesActivity.java b/src/org/linphone/PreferencesActivity.java
new file mode 100644
index 000000000..18468663e
--- /dev/null
+++ b/src/org/linphone/PreferencesActivity.java
@@ -0,0 +1,492 @@
+/*
+PreferencesActivity.java
+Copyright (C) 2010 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 static org.linphone.R.string.ec_calibrating;
+import static org.linphone.R.string.pref_codec_amr_key;
+import static org.linphone.R.string.pref_codec_amrwb_key;
+import static org.linphone.R.string.pref_codec_ilbc_key;
+import static org.linphone.R.string.pref_codec_speex16_key;
+import static org.linphone.R.string.pref_echo_cancellation_key;
+import static org.linphone.R.string.pref_echo_canceller_calibration_key;
+import static org.linphone.R.string.pref_echo_limiter_key;
+import static org.linphone.R.string.pref_media_encryption_key;
+import static org.linphone.R.string.pref_video_enable_key;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.linphone.LinphoneManager.EcCalibrationListener;
+import org.linphone.LinphoneManager.LinphoneConfigException;
+import org.linphone.core.LinphoneCore;
+import org.linphone.core.LinphoneCore.EcCalibratorStatus;
+import org.linphone.core.LinphoneCore.MediaEncryption;
+import org.linphone.core.LinphoneCoreException;
+import org.linphone.core.Log;
+import org.linphone.mediastream.Version;
+import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
+import org.linphone.mediastream.video.capture.hwconf.Hacks;
+import org.linphone.setup.SetupActivity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceScreen;
+
+public class PreferencesActivity extends LinphonePreferencesActivity implements EcCalibrationListener {
+ private Handler mHandler = new Handler();
+ private CheckBoxPreference ecCalibratePref;
+ private CheckBoxPreference elPref;
+ private CheckBoxPreference ecPref;
+ private ListPreference mencPref;
+ private int nbAccounts = 1;
+ private PreferenceCategory accounts;
+
+ private static final int ADD_SIP_ACCOUNT = 0x666;
+ private static final int ACCOUNTS_SETTINGS_ID = 1;
+ private static final int WIZARD_SETTINGS_ID = 2;
+ private static final int CAMERA_SETTINGS_ID = 6;
+ private static final int EXIT_SETTINGS_ID = 0;
+
+ private SharedPreferences prefs() {
+ return getPreferenceManager().getSharedPreferences();
+ }
+
+ private CheckBoxPreference findCheckbox(int key) {
+ return (CheckBoxPreference) findPreference(getString(key));
+ }
+
+ private void detectAudioCodec(int id, String mime, int rate, boolean hide) {
+ boolean enable = LinphoneService.isReady() && LinphoneManager.getLc().findPayloadType(mime, rate)!=null;
+ Preference cb = findPreference(id);
+ cb.setEnabled(enable);
+ if (hide && !enable) {
+ cb.setLayoutResource(R.layout.hidden);
+ }
+ }
+
+ private void detectVideoCodec(int id, String mime) {
+ findPreference(id).setEnabled(LinphoneManager.getInstance().detectVideoCodec(mime));
+ }
+
+ private void createDynamicAccountsPreferences() {
+ accounts = (PreferenceCategory) getPreferenceScreen().getPreference(ACCOUNTS_SETTINGS_ID);
+ accounts.removeAll();
+
+ // Get already configured extra accounts
+ SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ nbAccounts = prefs.getInt(getString(R.string.pref_extra_accounts), 0);
+ for (int i = 0; i < nbAccounts; i++) {
+ // For each, add menus to configure it
+ addExtraAccountPreferencesButton(accounts, i, false);
+ }
+ }
+
+ public int getNbAccountsExtra() {
+ return nbAccounts;
+ }
+
+ private void addExitButton() {
+ Preference me = (Preference) getPreferenceScreen().getPreference(EXIT_SETTINGS_ID);
+
+ me.setOnPreferenceClickListener(new OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference preference) {
+ Intent result = new Intent();
+ result.putExtra("Exit", true);
+ setResult(Activity.RESULT_FIRST_USER, result);
+ finish();
+ return true;
+ }
+ });
+ }
+
+ private void addExtraAccountPreferencesButton(PreferenceCategory parent, final int n, boolean isNewAccount) {
+ SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ if (isNewAccount) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(getString(R.string.pref_extra_accounts), n+1);
+ editor.commit();
+ }
+
+ Preference me = new Preference(PreferencesActivity.this);
+ String keyUsername = getString(R.string.pref_username_key);
+ String keyDomain = getString(R.string.pref_domain_key);
+ if (n > 0) {
+ keyUsername += n + "";
+ keyDomain += n + "";
+ }
+ if (prefs.getString(keyUsername, null) == null) {
+ me.setTitle(getString(R.string.pref_sipaccount));
+ } else {
+ me.setTitle(prefs.getString(keyUsername, "") + "@" + prefs.getString(keyDomain, ""));
+ }
+
+ me.setOnPreferenceClickListener(new OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference preference) {
+ Intent i = new Intent();
+ i.putExtra("Account", n);
+ i.setClass(PreferencesActivity.this, AccountPreferencesActivity.class);
+ startActivityForResult(i, ADD_SIP_ACCOUNT);
+ return false;
+ }
+ });
+ parent.addPreference(me);
+ }
+
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == ADD_SIP_ACCOUNT) {
+ //Verify if last created account is filled
+ SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ int n = prefs.getInt(getString(R.string.pref_extra_accounts), 1);
+ String keyUsername = getString(R.string.pref_username_key) + (n-1 == 0 ? "" : Integer.toString(n-1));
+
+ if (prefs.getString(keyUsername, "").equals("")) {
+ //If not, we suppress it to not display a blank field
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(getString(R.string.pref_extra_accounts), n-1);
+ editor.commit();
+ }
+
+ createDynamicAccountsPreferences();
+ }
+
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ private void addWizardPreferenceButton() {
+ Preference wizard = (Preference) getPreferenceScreen().getPreference(WIZARD_SETTINGS_ID);
+ wizard.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference preference) {
+ Intent intent = new Intent(getApplicationContext(), SetupActivity.class);
+ finish();
+ startActivity(intent);
+ return true;
+ }
+ });
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ // Load the preferences from an XML resource
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.preferences);
+
+ addExitButton();
+
+ if (!getResources().getBoolean(R.bool.hide_accounts)) {
+ createDynamicAccountsPreferences();
+ } else {
+ // Hide category
+ PreferenceCategory accounts = (PreferenceCategory) getPreferenceScreen().getPreference(ACCOUNTS_SETTINGS_ID);
+ accounts.removeAll();
+ accounts.setLayoutResource(R.layout.hidden);
+ }
+
+ if (getResources().getBoolean(R.bool.hide_wizard)) {
+ Preference wizard = (Preference) getPreferenceScreen().getPreference(WIZARD_SETTINGS_ID);
+ wizard.setLayoutResource(R.layout.hidden);
+ } else {
+ addWizardPreferenceButton();
+ }
+
+ addTransportChecboxesListener();
+
+ ecCalibratePref = (CheckBoxPreference) findPreference(pref_echo_canceller_calibration_key);
+ ecCalibratePref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference preference) {
+ startEcCalibration();
+ return false;
+ }
+ });
+ ecPref = (CheckBoxPreference) findPreference(pref_echo_cancellation_key);
+ elPref = (CheckBoxPreference) findPreference(pref_echo_limiter_key);
+ mencPref = (ListPreference) findPreference(pref_media_encryption_key);
+
+ boolean fastCpu = Version.isArmv7();
+ if (fastCpu) {
+ detectAudioCodec(pref_codec_ilbc_key, "iLBC", 8000, false);
+ findPreference(pref_codec_speex16_key).setEnabled(true);
+ //findPreference(pref_codec_speex32_key)).setEnabled(enableIlbc);
+ }
+ findPreference(pref_echo_limiter_key).setEnabled(true);
+
+ initializeMediaEncryptionPreferences();
+
+ detectAudioCodec(pref_codec_amr_key,"AMR", 8000, false);
+ detectAudioCodec(pref_codec_amrwb_key,"AMR-WB", 16000, false);
+ //detectAudioCodec(R.string.pref_codec_silk8_key,"SILK",8000, true);
+ //detectAudioCodec(R.string.pref_codec_silk12_key,"SILK",12000, true);
+ detectAudioCodec(R.string.pref_codec_silk16_key,"SILK",16000, true);
+ detectAudioCodec(R.string.pref_codec_silk24_key,"SILK",24000, true);
+ detectAudioCodec(R.string.pref_codec_g729_key,"G729",8000, true);
+
+ // No video
+ if (!Version.isVideoCapable()) {
+ uncheckAndDisableCheckbox(pref_video_enable_key);
+ } else if (!AndroidCameraConfiguration.hasFrontCamera()) {
+ uncheckDisableAndHideCheckbox(R.string.pref_video_use_front_camera_key);
+ }
+
+ if (prefs().getBoolean(LinphoneActivity.PREF_FIRST_LAUNCH,true)) {
+ doOnFirstLaunch();
+ }
+ if (Hacks.hasBuiltInEchoCanceller()) {
+ uncheckDisableAndHideCheckbox(R.string.pref_echo_limiter_key);
+ uncheckDisableAndHideCheckbox(R.string.pref_echo_cancellation_key);
+ uncheckDisableAndHideCheckbox(R.string.pref_echo_canceller_calibration_key);
+ }
+
+
+ detectVideoCodec(R.string.pref_video_codec_h264_key, "H264");
+ if (!Version.hasNeon())
+ {
+ // Android without neon doesn't support H264
+ findPreference(R.string.pref_video_codec_h264_key).setEnabled(false);
+ findPreference(R.string.pref_video_codec_h264_key).setDefaultValue(false);
+ }
+
+ addEchoPrefsListener();
+
+ if (Hacks.needSoftvolume()) checkAndDisableCheckbox(R.string.pref_audio_soft_volume_key);
+
+ if (!LinphoneManager.getLc().isTunnelAvailable()){
+ hidePreferenceCategory(R.string.pref_tunnel_key);
+ }
+
+ if (getResources().getBoolean(R.bool.hide_camera_settings)) {
+ PreferenceScreen screen = getPreferenceScreen();
+ PreferenceCategory videoSettings = (PreferenceCategory) screen.getPreference(CAMERA_SETTINGS_ID);
+ videoSettings.removeAll();
+ videoSettings.setLayoutResource(R.layout.hidden);
+
+ CheckBoxPreference enableVideo = (CheckBoxPreference) findPreference(R.string.pref_video_enable_key);
+ enableVideo.setLayoutResource(R.layout.hidden);
+ }
+ }
+
+ private void hidePreferenceCategory(int key) {
+ PreferenceCategory p = (PreferenceCategory) findPreference(key);
+ p.removeAll();
+ p.setLayoutResource(R.layout.hidden);
+ }
+
+ private void doOnFirstLaunch() {
+ manageCheckbox(R.string.pref_echo_limiter_key, !Hacks.hasBuiltInEchoCanceller(), true, false);
+ prefs().edit().putBoolean(LinphoneActivity.PREF_FIRST_LAUNCH, false).commit();
+ }
+
+ private void initializeMediaEncryptionPreferences() {
+ LinphoneCore lc=LinphoneManager.getLc();
+ boolean hasZrtp=lc.mediaEncryptionSupported(MediaEncryption.ZRTP);
+ boolean hasSrtp=lc.mediaEncryptionSupported(MediaEncryption.SRTP);
+ if (!hasSrtp && !hasZrtp){
+ mencPref.setEnabled(false);
+ }else{
+ List mencEntries=new ArrayList();
+ List mencEntryValues=new ArrayList();
+ mencEntries.add(getString(R.string.media_encryption_none));
+ mencEntryValues.add(getString(R.string.pref_media_encryption_key_none));
+ if (hasSrtp){
+ mencEntries.add(getString(R.string.media_encryption_srtp));
+ mencEntryValues.add(getString(R.string.pref_media_encryption_key_srtp));
+ }
+ if (hasZrtp){
+ mencEntries.add(getString(R.string.media_encryption_zrtp));
+ mencEntryValues.add(getString(R.string.pref_media_encryption_key_zrtp));
+ }
+ CharSequence[] contents=new CharSequence[mencEntries.size()];
+ mencEntries.toArray(contents);
+ mencPref.setEntries(contents);
+ contents=new CharSequence[mencEntryValues.size()];
+ mencEntryValues.toArray(contents);
+ mencPref.setEntryValues(contents);
+ mencPref.setDefaultValue(getString(R.string.media_encryption_none));
+ //mencPref.setValueIndex(mencPref.findIndexOfValue(getString(R.string.media_encryption_none)));
+ }
+ }
+
+ private void addEchoPrefsListener(){
+ OnPreferenceChangeListener ec_listener=new OnPreferenceChangeListener(){
+ public boolean onPreferenceChange(Preference arg0, Object newValue) {
+ Boolean val=(Boolean)newValue;
+ if (val){
+ elPref.setChecked(!val);
+ }
+ return true;
+ }
+ };
+ OnPreferenceChangeListener el_listener=new OnPreferenceChangeListener(){
+ public boolean onPreferenceChange(Preference arg0, Object newValue) {
+ Boolean val=(Boolean)newValue;
+ if (val){
+ ecPref.setChecked(!val);
+ }
+ return true;
+ }
+ };
+ ecPref.setOnPreferenceChangeListener(ec_listener);
+ elPref.setOnPreferenceChangeListener(el_listener);
+ }
+
+ private void addTransportChecboxesListener() {
+
+ final List checkboxes = Arrays.asList(
+ findCheckbox(R.string.pref_transport_udp_key)
+ ,findCheckbox(R.string.pref_transport_tcp_key)
+ ,findCheckbox(R.string.pref_transport_tls_key)
+ );
+
+
+ OnPreferenceChangeListener changedListener = new OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if ((Boolean) newValue) {
+ for (CheckBoxPreference p : checkboxes) {
+ if (p == preference) continue;
+ p.setChecked(false);
+ }
+ return true;
+ } else {
+ for (CheckBoxPreference p : checkboxes) {
+ if (p == preference) continue;
+ if (p.isChecked()) return true;
+ }
+ return false;
+ }
+ }
+ };
+
+ OnPreferenceClickListener clickListener = new OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference preference) {
+ // Forbid no protocol selection
+
+ if (((CheckBoxPreference) preference).isChecked()) {
+ // Trying to unckeck
+ for (CheckBoxPreference p : checkboxes) {
+ if (p == preference) continue;
+ if (p.isChecked()) return false;
+ }
+ /*Toast.makeText(LinphonePreferencesActivity.this,
+ getString(R.string.at_least_a_protocol),
+ Toast.LENGTH_SHORT).show();*/
+ return true;
+ }
+ return false;
+ }
+ };
+
+ for (CheckBoxPreference c : checkboxes) {
+ c.setOnPreferenceChangeListener(changedListener);
+ c.setOnPreferenceClickListener(clickListener);
+ }
+ }
+
+ private synchronized void startEcCalibration() {
+ try {
+ LinphoneManager.getInstance().startEcCalibration(this);
+
+ ecCalibratePref.setSummary(ec_calibrating);
+ ecCalibratePref.getEditor().putBoolean(getString(pref_echo_canceller_calibration_key), false).commit();
+ } catch (LinphoneCoreException e) {
+ Log.w(e, "Cannot calibrate EC");
+ }
+ }
+
+ public void onEcCalibrationStatus(final EcCalibratorStatus status, final int delayMs) {
+
+ mHandler.post(new Runnable() {
+ public void run() {
+ if (status == EcCalibratorStatus.Done) {
+ ecCalibratePref.setSummary(String.format(getString(R.string.ec_calibrated), delayMs));
+ ecCalibratePref.setChecked(true);
+
+ } else if (status == EcCalibratorStatus.Failed) {
+ ecCalibratePref.setSummary(R.string.failed);
+ ecCalibratePref.setChecked(false);
+ elPref.setChecked(true);
+ ecPref.setChecked(false);
+ }
+ }
+ });
+ }
+
+ private void uncheckDisableAndHideCheckbox(int key) {
+ manageCheckbox(key, false, false, true);
+ }
+
+ private void uncheckAndDisableCheckbox(int key) {
+ manageCheckbox(key, false, false, false);
+ }
+ private void checkAndDisableCheckbox(int key) {
+ manageCheckbox(key, true, false, false);
+ }
+ private void manageCheckbox(int key, boolean value, boolean enabled, boolean hidden) {
+ CheckBoxPreference box = (CheckBoxPreference) findPreference(key);
+ box.setEnabled(enabled);
+ box.setChecked(value);
+ writeBoolean(key, value);
+ if (hidden) box.setLayoutResource(R.layout.hidden);
+ }
+
+ private Preference findPreference(int key) {
+ return getPreferenceManager().findPreference(getString(key));
+ }
+
+ private void writeBoolean(int key, boolean value) {
+ prefs().edit().putBoolean(getString(key), value).commit();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ if (!isFinishing()) return;
+
+ LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
+
+ if (lc != null && (lc.isInComingInvitePending() || lc.isIncall())) {
+ Log.w("Call in progress => settings not applied");
+ return;
+ }
+
+ try {
+ LinphoneManager.getInstance().initFromConf();
+ lc.setVideoPolicy(LinphoneManager.getInstance().isAutoInitiateVideoCalls(), LinphoneManager.getInstance().isAutoAcceptCamera());
+ } catch (LinphoneException e) {
+ if (! (e instanceof LinphoneConfigException)) {
+ Log.e(e, "Cannot update config");
+ return;
+ }
+
+ LinphoneActivity.instance().showPreferenceErrorDialog(e.getMessage());
+ }
+ }
+
+}
diff --git a/src/org/linphone/StatusFragment.java b/src/org/linphone/StatusFragment.java
new file mode 100644
index 000000000..2df066da7
--- /dev/null
+++ b/src/org/linphone/StatusFragment.java
@@ -0,0 +1,199 @@
+package org.linphone;
+/*
+StatusFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCore.MediaEncryption;
+import org.linphone.core.LinphoneCore.RegistrationState;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class StatusFragment extends Fragment {
+ private static StatusFragment instance;
+ private Handler mHandler = new Handler();
+ private Handler refreshHandler = new Handler();
+ private TextView statusText;
+ private ImageView statusLed, callQuality, encryption;
+ private Runnable mCallQualityUpdater;
+ private boolean isInCall, isAttached = false;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ instance = this;
+ View view = inflater.inflate(R.layout.status, container, false);
+
+ statusText = (TextView) view.findViewById(R.id.statusText);
+ statusLed = (ImageView) view.findViewById(R.id.statusLed);
+ callQuality = (ImageView) view.findViewById(R.id.callQuality);
+ encryption = (ImageView) view.findViewById(R.id.encryption);
+
+ return view;
+ }
+
+ /**
+ * @return null if not ready yet
+ */
+ public static StatusFragment instance() {
+ return instance;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ isAttached = true;
+
+ if (activity instanceof LinphoneActivity) {
+ ((LinphoneActivity) activity).updateStatusFragment(this);
+ isInCall = false;
+ } else if (activity instanceof InCallActivity) {
+ ((InCallActivity) activity).updateStatusFragment(this);
+ isInCall = true;
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ isAttached = false;
+ }
+
+ public void registrationStateChanged(final RegistrationState state) {
+ if (!isAttached)
+ return;
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (state == RegistrationState.RegistrationOk && LinphoneManager.getLc().getDefaultProxyConfig().isRegistered()) {
+ statusLed.setImageResource(R.drawable.led_connected);
+ statusText.setText(getString(R.string.status_connected));
+ } else {
+ statusLed.setImageResource(R.drawable.led_disconnected);
+ statusText.setText(getString(R.string.status_not_connected));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ private void startCallQuality() {
+ callQuality.setVisibility(View.VISIBLE);
+ refreshHandler.postDelayed(mCallQualityUpdater = new Runnable() {
+ LinphoneCall mCurrentCall = LinphoneManager.getLc()
+ .getCurrentCall();
+
+ public void run() {
+ if (mCurrentCall == null) {
+ mCallQualityUpdater = null;
+ return;
+ }
+
+ int oldQuality = 0;
+ float newQuality = mCurrentCall.getCurrentQuality();
+ if ((int) newQuality != oldQuality) {
+ updateQualityOfSignalIcon(newQuality);
+ }
+
+ if (isInCall) {
+ refreshHandler.postDelayed(this, 1000);
+ } else
+ mCallQualityUpdater = null;
+ }
+ }, 1000);
+ }
+
+ void updateQualityOfSignalIcon(float quality) {
+ if (quality >= 4) // Good Quality
+ {
+ callQuality.setImageResource(
+ R.drawable.call_quality_indicator_3);
+ } else if (quality >= 3) // Average quality
+ {
+ callQuality.setImageResource(
+ R.drawable.call_quality_indicator_2);
+ } else if (quality >= 2) // Low quality
+ {
+ callQuality.setImageResource(
+ R.drawable.call_quality_indicator_1);
+ } else if (quality >= 1) // Very low quality
+ {
+ callQuality.setImageResource(
+ R.drawable.call_quality_indicator_1);
+ } else // Worst quality
+ {
+ callQuality.setImageResource(
+ R.drawable.call_quality_indicator_0);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (isInCall) {
+ startCallQuality();
+ refreshEncryptionIcon();
+
+ // We are obviously connected
+ statusLed.setImageResource(R.drawable.led_connected);
+ statusText.setText(getString(R.string.status_connected));
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ if (mCallQualityUpdater != null) {
+ refreshHandler.removeCallbacks(mCallQualityUpdater);
+ mCallQualityUpdater = null;
+ }
+ }
+
+ public void refreshEncryptionIcon() {
+ LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
+ if (call != null && encryption != null) {
+ MediaEncryption mediaEncryption = call.getCurrentParamsCopy().getMediaEncryption();
+
+ encryption.setVisibility(View.VISIBLE);
+
+ if (mediaEncryption == MediaEncryption.SRTP || (mediaEncryption == MediaEncryption.ZRTP && call.isAuthenticationTokenVerified())) {
+ encryption.setImageResource(R.drawable.security_ok);
+ } else if (mediaEncryption == MediaEncryption.ZRTP && !call.isAuthenticationTokenVerified()) {
+ encryption.setImageResource(R.drawable.security_pending);
+ } else {
+ encryption.setImageResource(R.drawable.security_ko);
+ }
+ }
+ }
+}
diff --git a/src/org/linphone/UriPickerActivity.java b/src/org/linphone/UriPickerActivity.java
deleted file mode 100644
index bf6072664..000000000
--- a/src/org/linphone/UriPickerActivity.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
-LinphoneActivity.java
-Copyright (C) 2010 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.mediastream.Version;
-import org.linphone.ui.AddressAware;
-import org.linphone.ui.AddressText;
-
-import android.app.Activity;
-import android.app.TabActivity;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.TabWidget;
-import android.widget.TabHost.TabSpec;
-
-/**
- * @author Guillaume Beraudo
- */
-public class UriPickerActivity extends TabActivity implements ContactPicked {
- private static final String DIALER_TAB = "dialer";
- public static final String EXTRA_CALLEE_NAME = "callee_name";
- public static final String EXTRA_CALLEE_URI = "callee_uri";
- public static final String EXTRA_CALLEE_PHOTO_URI = "callee_photo_uri";
- public static final String EXTRA_PICKER_TYPE = "picker_type";
- public static final String EXTRA_PICKER_TYPE_ADD = "picker_type_add";
- public static final String EXTRA_PICKER_TYPE_TRANSFER = "picker_type_transfer";
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- fillTabHost();
- }
-
-
- private synchronized void fillTabHost() {
- if (((TabWidget) findViewById(android.R.id.tabs)).getChildCount() != 0) return;
-
- startActivityInTab("history",
- new Intent().setClass(this, HistoryActivity.class),
- R.string.tab_history, R.drawable.history_orange);
-
-
- startActivityInTab(DIALER_TAB,
- new Intent().setClass(this, DialerActivity.class).setData(getIntent().getData())
- .putExtra(EXTRA_PICKER_TYPE, getIntent().getStringExtra(EXTRA_PICKER_TYPE)),
- R.string.tab_dialer, R.drawable.dialer_orange);
-
-
- startActivityInTab("contact",
- new Intent().setClass(this, Version.sdkAboveOrEqual(Version.API05_ECLAIR_20) ?
- ContactPickerActivityNew.class : ContactPickerActivityOld.class),
- R.string.tab_contact, R.drawable.contact_orange);
-
-
- selectDialerTab();
- }
-
-
- private void selectDialerTab() {
- getTabHost().setCurrentTabByTag(DIALER_TAB);
- }
-
- private void startActivityInTab(String tag, Intent intent, int indicatorId, int drawableId) {
- Drawable tabDrawable = getResources().getDrawable(drawableId);
- TabSpec spec = getTabHost().newTabSpec(tag)
- .setIndicator(getString(indicatorId), tabDrawable)
- .setContent(intent);
- getTabHost().addTab(spec);
- }
-
-
-
- void terminate(String number, String name, Uri photo) {
- Intent intent = new Intent()
- .putExtra(EXTRA_CALLEE_NAME, name)
- .putExtra(EXTRA_CALLEE_URI, number)
- .putExtra(EXTRA_CALLEE_PHOTO_URI, photo);
- setResult(Activity.RESULT_OK, intent);
- finish();
- }
-
-
-
-
-
- public static class DialerActivity extends Activity implements OnClickListener {
-
- private AddressText mAddress;
- private Button addButton;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setContentView(R.layout.simplified_dialer);
- mAddress = (AddressText) findViewById(R.id.SipUri);
-
- addButton = (Button) findViewById(R.id.AddCallButton);
-// addButton.setCompoundDrawablePadding(100);
- addButton.setOnClickListener(this);
- String type = getIntent().getStringExtra(EXTRA_PICKER_TYPE);
- if (EXTRA_PICKER_TYPE_ADD.equals(type)) {
- addButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.incall_add_small, 0, 0);
- addButton.setText(getString(R.string.AddCallButtonText));
- } else if (EXTRA_PICKER_TYPE_TRANSFER.equals(type)) {
- addButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.picker_transfer, 0, 0);
- addButton.setText(getString(R.string.TransferCallButtonText));
- } else {
- throw new RuntimeException("unknown type");
- }
-
-// findViewById(R.id.AddCallCancelButton).setOnClickListener(this);
-
- ((AddressAware)findViewById(R.id.Dialer)).setAddressWidget(mAddress);
- ((AddressAware)findViewById(R.id.Erase)).setAddressWidget(mAddress);
- super.onCreate(savedInstanceState);
- }
-
- public void setContactAddress(String number, String name, Uri photo) {
- mAddress.setText(number);
- mAddress.setDisplayedName(name);
- mAddress.setPictureUri(photo);
- }
-
- @Override
- public void onClick(View v) {
- if (v == addButton) {
- UriPickerActivity parent = (UriPickerActivity) getParent();
- parent.terminate(mAddress.getText().toString(), mAddress.getDisplayedName(), mAddress.getPictureUri());
- } else {
- // propagate finish to parent through finishFromChild
- finish();
- }
- }
- }
-
-
- public void setAddressAndGoToDialer(String number, String name, Uri photo) {
- DialerActivity dialer = (DialerActivity) getLocalActivityManager().getActivity(DIALER_TAB);
- dialer.setContactAddress(number, name, photo);
- selectDialerTab();
- }
-
-
- @Override
- public void goToDialer() {
- selectDialerTab();
- }
-}
diff --git a/src/org/linphone/VideoCallActivity.java b/src/org/linphone/VideoCallActivity.java
deleted file mode 100755
index b80851b30..000000000
--- a/src/org/linphone/VideoCallActivity.java
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
-VideoCallActivity.java
-Copyright (C) 2010 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.LinphoneSimpleListener.LinphoneOnCallStateChangedListener;
-import org.linphone.compatibility.Compatibility;
-import org.linphone.core.LinphoneCall;
-import org.linphone.core.LinphoneCall.State;
-import org.linphone.core.LinphoneCallParams;
-import org.linphone.core.Log;
-import org.linphone.mediastream.Version;
-import org.linphone.mediastream.video.AndroidVideoWindowImpl;
-import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
-import org.linphone.ui.Numpad;
-import org.linphone.ui.ToggleImageButton;
-
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.opengl.GLSurfaceView;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.util.TypedValue;
-import android.view.Display;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnTouchListener;
-import android.view.WindowManager;
-import android.widget.Checkable;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.RelativeLayout.LayoutParams;
-
-/**
- * For Android SDK >= 5
- *
- * @author Guillaume Beraudo
- *
- */
-@TargetApi(5)
-public class VideoCallActivity extends Activity implements
- LinphoneOnCallStateChangedListener, OnClickListener {
- private final static int DELAY_BEFORE_HIDING_CONTROLS = 2000;
- private static final int numpadDialogId = 1;
-
- private SurfaceView mVideoViewReady;
- private SurfaceView mVideoCaptureViewReady;
- public static boolean launched = false;
- private LinphoneCall videoCall;
- private WakeLock mWakeLock;
- private Handler refreshHandler = new Handler();
- private Handler controlsHandler = new Handler();
- AndroidVideoWindowImpl androidVideoWindowImpl;
- private Runnable mCallQualityUpdater, mControls;
- private LinearLayout mControlsLayout;
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (!LinphoneManager.isInstanciated()
- || LinphoneManager.getLc().getCallsNb() == 0) {
- Log.e("No service running: avoid crash by finishing ", getClass()
- .getName());
- // super.onCreate called earlier
- finish();
- return;
- }
-
- setContentView(R.layout.videocall);
-
- SurfaceView videoView = (SurfaceView) findViewById(R.id.video_surface);
-
- // ((FrameLayout)
- // findViewById(R.id.video_frame)).bringChildToFront(findViewById(R.id.imageView1));
-
- SurfaceView captureView = (SurfaceView) findViewById(R.id.video_capture_surface);
- captureView.getHolder()
- .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
-
- /* force surfaces Z ordering */
- fixZOrder(videoView, captureView);
-
- androidVideoWindowImpl = new AndroidVideoWindowImpl(videoView,
- captureView);
- androidVideoWindowImpl
- .setListener(new AndroidVideoWindowImpl.VideoWindowListener() {
-
- public void onVideoRenderingSurfaceReady(
- AndroidVideoWindowImpl vw, SurfaceView surface) {
- LinphoneManager.getLc().setVideoWindow(vw);
- mVideoViewReady = surface;
- }
-
- public void onVideoRenderingSurfaceDestroyed(
- AndroidVideoWindowImpl vw) {
- Log.d("VIDEO WINDOW destroyed!\n");
- LinphoneManager.getLc().setVideoWindow(null);
- }
-
- public void onVideoPreviewSurfaceReady(
- AndroidVideoWindowImpl vw, SurfaceView surface) {
- mVideoCaptureViewReady = surface;
- LinphoneManager.getLc().setPreviewWindow(
- mVideoCaptureViewReady);
- }
-
- public void onVideoPreviewSurfaceDestroyed(
- AndroidVideoWindowImpl vw) {
- // Remove references kept in jni code and restart camera
- LinphoneManager.getLc().setPreviewWindow(null);
- }
- });
-
- androidVideoWindowImpl.init();
-
- videoCall = LinphoneManager.getLc().getCurrentCall();
- if (videoCall != null) {
- LinphoneManager lm = LinphoneManager.getInstance();
- if (!lm.shareMyCamera() && videoCall.cameraEnabled()) {
- lm.sendStaticImage(true);
- }
-
- updatePreview(videoCall.cameraEnabled());
- }
-
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.ON_AFTER_RELEASE, Log.TAG);
- mWakeLock.acquire();
-
- mControlsLayout = (LinearLayout) findViewById(R.id.incall_controls_layout);
- videoView.setOnTouchListener(new OnTouchListener() {
- public boolean onTouch(View v, MotionEvent event) {
- if (mControlsLayout != null
- && mControlsLayout.getVisibility() == View.GONE) {
- mControlsLayout.setVisibility(View.VISIBLE);
- controlsHandler.postDelayed(mControls = new Runnable() {
- public void run() {
- mControlsLayout.setVisibility(View.GONE);
- }
- }, DELAY_BEFORE_HIDING_CONTROLS);
-
- return true;
- }
- return false;
- }
- });
-
- if (!AndroidCameraConfiguration.hasSeveralCameras()) {
- View v=findViewById(R.id.switch_camera);
- if (v!=null) v.setVisibility(View.GONE);
- }
-
- if (Version.isXLargeScreen(this)) {
- findViewById(R.id.toggleMuteMic).setOnClickListener(this);
- findViewById(R.id.toggleSpeaker).setOnClickListener(this);
- findViewById(R.id.incallNumpadShow).setOnClickListener(this);
- findViewById(R.id.back).setOnClickListener(this);
- findViewById(R.id.incallHang).setOnClickListener(this);
- findViewById(R.id.switch_camera).setOnClickListener(this);
- findViewById(R.id.conf_simple_pause).setOnClickListener(this);
- findViewById(R.id.conf_simple_video).setOnClickListener(this);
-
- if (LinphoneManager.getInstance().isSpeakerOn()) {
- ToggleImageButton speaker = (ToggleImageButton) findViewById(R.id.toggleSpeaker);
- speaker.setChecked(true);
- speaker.setEnabled(false);
- }
- }
- }
-
- void updateQualityOfSignalIcon(float quality) {
- ImageView qos = (ImageView) findViewById(R.id.QoS);
- if (quality >= 4) // Good Quality
- {
- qos.setImageDrawable(getResources().getDrawable(
- R.drawable.stat_sys_signal_4));
- } else if (quality >= 3) // Average quality
- {
- qos.setImageDrawable(getResources().getDrawable(
- R.drawable.stat_sys_signal_3));
- } else if (quality >= 2) // Low quality
- {
- qos.setImageDrawable(getResources().getDrawable(
- R.drawable.stat_sys_signal_2));
- } else if (quality >= 1) // Very low quality
- {
- qos.setImageDrawable(getResources().getDrawable(
- R.drawable.stat_sys_signal_1));
- } else // Worst quality
- {
- qos.setImageDrawable(getResources().getDrawable(
- R.drawable.stat_sys_signal_0));
- }
- }
-
- private void rewriteToggleCameraItem(MenuItem item) {
- if (LinphoneManager.getLc().getCurrentCall().cameraEnabled()) {
- item.setTitle(getString(R.string.menu_videocall_toggle_camera_disable));
- } else {
- item.setTitle(getString(R.string.menu_videocall_toggle_camera_enable));
- }
- }
-
- private void rewriteChangeResolutionItem(MenuItem item) {
- if (BandwidthManager.getInstance().isUserRestriction()) {
- item.setTitle(getString(R.string.menu_videocall_change_resolution_when_low_resolution));
- } else {
- item.setTitle(getString(R.string.menu_videocall_change_resolution_when_high_resolution));
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- if (Version.isXLargeScreen(this))
- return false;
-
- // Inflate the currently selected menu XML resource.
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.videocall_activity_menu, menu);
-
- rewriteToggleCameraItem(menu
- .findItem(R.id.videocall_menu_toggle_camera));
- rewriteChangeResolutionItem(menu
- .findItem(R.id.videocall_menu_change_resolution));
-
- if (!AndroidCameraConfiguration.hasSeveralCameras()) {
- menu.findItem(R.id.videocall_menu_switch_camera).setVisible(false);
- }
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
- if (id == R.id.videocall_menu_back_to_dialer) {
- finish();
- LinphoneActivity.instance().startIncallActivity();
- }
- else if (id == R.id.videocall_menu_change_resolution) {
- LinphoneManager.getInstance().changeResolution();
- // previous call will cause graph reconstruction -> regive preview
- // window
- if (mVideoCaptureViewReady != null)
- LinphoneManager.getLc()
- .setPreviewWindow(mVideoCaptureViewReady);
- rewriteChangeResolutionItem(item);
- }
- else if (id == R.id.videocall_menu_terminate_call) {
- LinphoneManager.getInstance().terminateCall();
- }
- else if (id == R.id.videocall_menu_toggle_camera) {
- boolean camEnabled = LinphoneManager.getInstance()
- .toggleEnableCamera();
- updatePreview(camEnabled);
- Log.e("winwow camera enabled: " + camEnabled);
- rewriteToggleCameraItem(item);
- // previous call will cause graph reconstruction -> regive preview
- // window
- if (camEnabled) {
- if (mVideoCaptureViewReady != null)
- LinphoneManager.getLc().setPreviewWindow(
- mVideoCaptureViewReady);
- } else
- LinphoneManager.getLc().setPreviewWindow(null);
- }
- else if (id == R.id.videocall_menu_switch_camera) {
- int videoDeviceId = LinphoneManager.getLc().getVideoDevice();
- videoDeviceId = (videoDeviceId + 1) % AndroidCameraConfiguration.retrieveCameras().length;
- LinphoneManager.getLc().setVideoDevice(videoDeviceId);
- CallManager.getInstance().updateCall();
- // previous call will cause graph reconstruction -> regive preview
- // window
- if (mVideoCaptureViewReady != null)
- LinphoneManager.getLc()
- .setPreviewWindow(mVideoCaptureViewReady);
- }
- else {
- Log.e("Unknown menu item [", item, "]");
- }
- return true;
- }
-
- void updatePreview(boolean cameraCaptureEnabled) {
- mVideoCaptureViewReady = null;
- if (cameraCaptureEnabled) {
- findViewById(R.id.imageView1).setVisibility(View.INVISIBLE);
- findViewById(R.id.video_capture_surface)
- .setVisibility(View.VISIBLE);
- } else {
- findViewById(R.id.video_capture_surface).setVisibility(
- View.INVISIBLE);
- findViewById(R.id.imageView1).setVisibility(View.VISIBLE);
- }
- findViewById(R.id.video_frame).requestLayout();
- }
-
- void fixZOrder(SurfaceView video, SurfaceView preview) {
- video.setZOrderOnTop(false);
- preview.setZOrderOnTop(true);
- }
-
- @Override
- protected void onResume() {
- if (!LinphoneManager.getLc().isIncall())
- finish();
-
- super.onResume();
- if (mVideoViewReady != null)
- ((GLSurfaceView) mVideoViewReady).onResume();
- synchronized (androidVideoWindowImpl) {
- LinphoneManager.getLc().setVideoWindow(androidVideoWindowImpl);
- }
- launched = true;
- LinphoneManager.addListener(this);
-
- refreshHandler.postDelayed(mCallQualityUpdater = new Runnable() {
- LinphoneCall mCurrentCall = LinphoneManager.getLc()
- .getCurrentCall();
-
- public void run() {
- if (mCurrentCall == null) {
- mCallQualityUpdater = null;
- return;
- }
- int oldQuality = 0;
- float newQuality = mCurrentCall.getCurrentQuality();
- if ((int) newQuality != oldQuality) {
- updateQualityOfSignalIcon(newQuality);
- }
- if (launched) {
- refreshHandler.postDelayed(this, 1000);
- } else
- mCallQualityUpdater = null;
- }
- }, 1000);
-
- if (mControlsLayout != null)
- mControlsLayout.setVisibility(View.GONE);
-
- if (videoCall != null && LinphoneManager.getInstance().shareMyCamera()) {
- videoCall.enableCamera(true);
- updatePreview(videoCall.cameraEnabled());
- }
- }
-
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (LinphoneUtils.onKeyVolumeAdjust(keyCode))
- return true;
- if (Version.isXLargeScreen(this) && LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) {
- return true;
- } else if (!Version.isXLargeScreen(this) && keyCode == KeyEvent.KEYCODE_BACK) {
- LinphoneActivity.instance().startIncallActivity();
- finish();
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- protected void onDestroy() {
- if (androidVideoWindowImpl != null) { // Prevent linphone from crashing
- // if correspondent hang up
- // while you are rotating
- androidVideoWindowImpl.release();
- }
- super.onDestroy();
- }
-
- @Override
- protected void onPause() {
- Log.d("onPause VideoCallActivity (isFinishing:", isFinishing(),
- ", inCall:", LinphoneManager.getLc().isIncall(), ")");
- LinphoneManager.removeListener(this);
-
- // Send NoWebcam since Android 4.0 can't get the video from the
- // webcam if the activity is not in foreground
- if (videoCall != null)
- videoCall.enableCamera(false);
-
- if (isFinishing()) {
- videoCall = null; // release reference
- }
- launched = false;
- synchronized (androidVideoWindowImpl) {
- /*
- * this call will destroy native opengl renderer which is used by
- * androidVideoWindowImpl
- */
- LinphoneManager.getLc().setVideoWindow(null);
- }
-
- if (mCallQualityUpdater != null) {
- refreshHandler.removeCallbacks(mCallQualityUpdater);
- mCallQualityUpdater = null;
- }
- if (mControls != null) {
- controlsHandler.removeCallbacks(mControls);
- mControls = null;
- }
-
- if (mWakeLock.isHeld())
- mWakeLock.release();
- super.onPause();
- if (mVideoViewReady != null)
- ((GLSurfaceView) mVideoViewReady).onPause();
- }
-
- @Override
- public void onCallStateChanged(LinphoneCall call, State state,
- String message) {
- if (call == videoCall && state == State.CallEnd) {
- BandwidthManager.getInstance().setUserRestriction(false);
- LinphoneManager.getInstance().resetCameraFromPreferences();
- finish();
- } else if (!call.getCurrentParamsCopy().getVideoEnabled()) {
- finish();
- }
- }
-
- private int dpToPixels(int dp){
- Resources r = getResources();
- int px = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
- r.getDisplayMetrics());
- return px;
- }
-
- private void resizePreview() {
- Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay();
-
- int rotation = Compatibility.getRotation(display);
- LayoutParams params;
-
- int w, h;
- if (Version.isXLargeScreen(this)) {
- w = 176;
- h = 148;
- } else {
- w = 74;
- h = 88;
- }
-
- if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
- params = new LayoutParams(dpToPixels(h), dpToPixels(w));
- } else {
- params = new LayoutParams(dpToPixels(w), dpToPixels(h));
- }
- params.setMargins(0, 0, 15, 15);
- params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
- params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
- if (mVideoViewReady != null && mVideoCaptureViewReady != null)
- mVideoCaptureViewReady.setLayoutParams(params);
- }
-
- public void onConfigurationChanged(Configuration newConfig) {
- resizePreview();
- super.onConfigurationChanged(null);
- }
-
- private void resetControlsLayoutExpiration() {
- if (mControls != null) {
- controlsHandler.removeCallbacks(mControls);
- }
-
- controlsHandler.postDelayed(mControls = new Runnable() {
- public void run() {
- mControlsLayout.setVisibility(View.GONE);
- }
- }, DELAY_BEFORE_HIDING_CONTROLS);
- }
-
- public void onClick(View v) {
- resetControlsLayoutExpiration();
- int id = v.getId();
- if (id == R.id.incallHang) {
- terminateCurrentCallOrConferenceOrAll();
- }
- else if (id == R.id.toggleSpeaker) {
- if (((Checkable) v).isChecked()) {
- LinphoneManager.getInstance().routeAudioToSpeaker();
- } else {
- LinphoneManager.getInstance().routeAudioToReceiver();
- }
- }
- else if (id == R.id.incallNumpadShow) {
- showDialog(numpadDialogId);
- }
- else if (id == R.id.toggleMuteMic) {
- LinphoneManager.getLc().muteMic(((Checkable) v).isChecked());
- }
- else if (id == R.id.switch_camera) {
- int videoDeviceId = LinphoneManager.getLc().getVideoDevice();
- videoDeviceId = (videoDeviceId + 1) % AndroidCameraConfiguration.retrieveCameras().length;
- LinphoneManager.getLc().setVideoDevice(videoDeviceId);
- CallManager.getInstance().updateCall();
- // previous call will cause graph reconstruction -> regive preview
- // window
- if (mVideoCaptureViewReady != null)
- LinphoneManager.getLc()
- .setPreviewWindow(mVideoCaptureViewReady);
- }
- else if (id == R.id.conf_simple_pause) {
- finish();
- LinphoneActivity.instance().startIncallActivity();
- LinphoneManager.getLc().pauseCall(videoCall);
- }
- else if (id == R.id.conf_simple_video) {
- LinphoneCallParams params = videoCall.getCurrentParamsCopy();
- params.setVideoEnabled(false);
- LinphoneManager.getLc().updateCall(videoCall, params);
- }
- else if (id == R.id.back) {
- finish();
- LinphoneActivity.instance().startIncallActivity();
- }
- }
-
- protected Dialog onCreateDialog(final int id) {
- switch (id) {
- case numpadDialogId:
- Numpad numpad = new Numpad(this, true);
- return new AlertDialog.Builder(this)
- .setView(numpad)
- .setPositiveButton(R.string.close_button_text,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int whichButton) {
- dismissDialog(id);
- }
- }).create();
- default:
- throw new IllegalArgumentException("unkown dialog id " + id);
- }
- }
-
- private void terminateCurrentCallOrConferenceOrAll() {
- LinphoneCall currentCall = LinphoneManager.getLc().getCurrentCall();
- if (currentCall != null) {
- LinphoneManager.getLc().terminateCall(currentCall);
- } else if (LinphoneManager.getLc().isInConference()) {
- LinphoneManager.getLc().terminateConference();
- } else {
- LinphoneManager.getLc().terminateAllCalls();
- }
- finish();
- }
-}
diff --git a/src/org/linphone/VideoCallFragment.java b/src/org/linphone/VideoCallFragment.java
new file mode 100644
index 000000000..816eda5a3
--- /dev/null
+++ b/src/org/linphone/VideoCallFragment.java
@@ -0,0 +1,177 @@
+package org.linphone;
+/*
+VideoCallFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.core.LinphoneCore;
+import org.linphone.core.Log;
+import org.linphone.mediastream.video.AndroidVideoWindowImpl;
+import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+
+/**
+ * @author Sylvain Berfini
+ */
+@TargetApi(5)
+public class VideoCallFragment extends Fragment {
+ private static VideoCallFragment instance;
+ private WakeLock mWakeLock;
+ private SurfaceView mVideoView;
+ private SurfaceView mCaptureView;
+ private AndroidVideoWindowImpl androidVideoWindowImpl;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ instance = this;
+ View view = inflater.inflate(R.layout.video, container, false);
+
+ mVideoView = (SurfaceView) view.findViewById(R.id.videoSurface);
+ mCaptureView = (SurfaceView) view.findViewById(R.id.videoCaptureSurface);
+ mCaptureView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // Warning useless because value is ignored and automatically set by new APIs.
+
+ /* force surfaces Z ordering */
+ fixZOrder(mVideoView, mCaptureView);
+
+ androidVideoWindowImpl = new AndroidVideoWindowImpl(mVideoView, mCaptureView);
+ androidVideoWindowImpl.setListener(new AndroidVideoWindowImpl.VideoWindowListener() {
+ public void onVideoRenderingSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView surface) {
+ LinphoneManager.getLc().setVideoWindow(vw);
+ mVideoView = surface;
+ }
+
+ public void onVideoRenderingSurfaceDestroyed(AndroidVideoWindowImpl vw) {
+ Log.d("VIDEO WINDOW destroyed!\n");
+ LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
+ if (lc != null) {
+ lc.setVideoWindow(null);
+ }
+ }
+
+ public void onVideoPreviewSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView surface) {
+ mCaptureView = surface;
+ LinphoneManager.getLc().setPreviewWindow(mCaptureView);
+ }
+
+ public void onVideoPreviewSurfaceDestroyed(AndroidVideoWindowImpl vw) {
+ // Remove references kept in jni code and restart camera
+ LinphoneManager.getLc().setPreviewWindow(null);
+ }
+ });
+ androidVideoWindowImpl.init();
+
+ PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, Log.TAG);
+
+ mVideoView.setOnTouchListener(new OnTouchListener() {
+ public boolean onTouch(View v, MotionEvent event) {
+ InCallActivity.instance().displayVideoCallControlsIfHidden();
+ return false;
+ }
+ });
+
+ return view;
+ }
+
+ /**
+ * @return null if not ready yet
+ */
+ public static VideoCallFragment instance() {
+ return instance;
+ }
+
+ private void fixZOrder(SurfaceView video, SurfaceView preview) {
+ video.setZOrderOnTop(false);
+ preview.setZOrderOnTop(true);
+ preview.setZOrderMediaOverlay(true); // Needed to be able to display control layout over
+ }
+
+ public void switchCamera() {
+ try {
+ int videoDeviceId = LinphoneManager.getLc().getVideoDevice();
+ videoDeviceId = (videoDeviceId + 1) % AndroidCameraConfiguration.retrieveCameras().length;
+ LinphoneManager.getLc().setVideoDevice(videoDeviceId);
+ CallManager.getInstance().updateCall();
+
+ // previous call will cause graph reconstruction -> regive preview
+ // window
+ if (mCaptureView != null) {
+ LinphoneManager.getLc().setPreviewWindow(mCaptureView);
+ }
+ } catch (ArithmeticException ae) {
+ Log.e("Cannot swtich camera : no camera");
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (mVideoView != null)
+ ((GLSurfaceView) mVideoView).onResume();
+
+ if (androidVideoWindowImpl != null) {
+ synchronized (androidVideoWindowImpl) {
+ LinphoneManager.getLc().setVideoWindow(androidVideoWindowImpl);
+ }
+ }
+
+ mWakeLock.acquire();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (androidVideoWindowImpl != null) {
+ // Prevent linphone from crashing if correspondent hang up while you are rotating
+ androidVideoWindowImpl.release();
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public void onPause() {
+ synchronized (androidVideoWindowImpl) {
+ /*
+ * this call will destroy native opengl renderer which is used by
+ * androidVideoWindowImpl
+ */
+ LinphoneManager.getLc().setVideoWindow(null);
+ }
+
+ if (mWakeLock.isHeld())
+ mWakeLock.release();
+
+ super.onPause();
+
+ if (mVideoView != null)
+ ((GLSurfaceView) mVideoView).onPause();
+ }
+}
diff --git a/src/org/linphone/compatibility/API4Compatibility.java b/src/org/linphone/compatibility/API4Compatibility.java
deleted file mode 100644
index 62aad0f7b..000000000
--- a/src/org/linphone/compatibility/API4Compatibility.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.linphone.compatibility;
-
-import android.view.Display;
-
-public class API4Compatibility {
-
- public static int getRotation(Display display) {
- return display.getOrientation();
- }
-}
diff --git a/src/org/linphone/compatibility/API8Compatibility.java b/src/org/linphone/compatibility/API8Compatibility.java
deleted file mode 100644
index 07567b09d..000000000
--- a/src/org/linphone/compatibility/API8Compatibility.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.linphone.compatibility;
-
-import android.view.Display;
-
-public class API8Compatibility {
-
- public static int getRotation(Display display) {
- return display.getRotation();
- }
-}
diff --git a/src/org/linphone/compatibility/ApiFivePlus.java b/src/org/linphone/compatibility/ApiFivePlus.java
new file mode 100644
index 000000000..f62b6e54e
--- /dev/null
+++ b/src/org/linphone/compatibility/ApiFivePlus.java
@@ -0,0 +1,145 @@
+package org.linphone.compatibility;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.linphone.mediastream.Version;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Contacts.Data;
+import android.provider.ContactsContract.Intents.Insert;
+
+/*
+ApiFivePlus.java
+Copyright (C) 2012 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.
+*/
+/**
+ * @author Sylvain Berfini
+ */
+@TargetApi(5)
+public class ApiFivePlus {
+ public static void overridePendingTransition(Activity activity, int idAnimIn, int idAnimOut) {
+ activity.overridePendingTransition(idAnimIn, idAnimOut);
+ }
+
+ public static Intent prepareAddContactIntent(String displayName, String sipUri) {
+ Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+ intent.putExtra(ContactsContract.Intents.Insert.NAME, displayName);
+
+ if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
+ ArrayList data = new ArrayList();
+ ContentValues sipAddressRow = new ContentValues();
+ sipAddressRow.put(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE);
+ sipAddressRow.put(SipAddress.SIP_ADDRESS, sipUri);
+ data.add(sipAddressRow);
+ intent.putParcelableArrayListExtra(Insert.DATA, data);
+ } else {
+ // VoIP field not available, we store the address in the IM field
+ intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, sipUri);
+ intent.putExtra(ContactsContract.Intents.Insert.IM_PROTOCOL, "sip");
+ }
+
+ return intent;
+ }
+
+ public static List extractContactNumbersAndAddresses(String id, ContentResolver cr) {
+ List list = new ArrayList();
+
+ Uri uri = ContactsContract.Data.CONTENT_URI;
+ String[] projection = {ContactsContract.CommonDataKinds.Im.DATA};
+
+ // SIP addresses
+ if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
+ String selection = new StringBuilder()
+ .append(ContactsContract.Data.CONTACT_ID)
+ .append(" = ? AND ")
+ .append(ContactsContract.Data.MIMETYPE)
+ .append(" = '")
+ .append(ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
+ .append("'")
+ .toString();
+ projection = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS};
+ Cursor c = cr.query(uri, projection, selection, new String[]{id}, null);
+
+ int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
+ while (c.moveToNext()) {
+ list.add("sip:" + c.getString(nbId));
+ }
+ c.close();
+ } else {
+ String selection = new StringBuilder()
+ .append(ContactsContract.Data.CONTACT_ID).append(" = ? AND ")
+ .append(ContactsContract.Data.MIMETYPE).append(" = '")
+ .append(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
+ .append("' AND lower(")
+ .append(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL)
+ .append(") = 'sip'")
+ .toString();
+ Cursor c = cr.query(uri, projection, selection, new String[]{id}, null);
+
+ int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA);
+ while (c.moveToNext()) {
+ list.add("sip:" + c.getString(nbId));
+ }
+ c.close();
+ }
+
+ // Phone Numbers
+ Cursor c = cr.query(Phone.CONTENT_URI, null, Phone.CONTACT_ID + " = " + id, null, null);
+ while (c.moveToNext()) {
+ String number = c.getString(c.getColumnIndex(Phone.NUMBER));
+ list.add(number);
+ }
+ c.close();
+
+ return list;
+ }
+
+ public static Cursor getContactsCursor(ContentResolver cr) {
+ return cr.query(ContactsContract.Contacts.CONTENT_URI, null, ContactsContract.Contacts.DISPLAY_NAME + " IS NOT NULL", null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");
+ }
+
+ public static String getContactDisplayName(Cursor cursor) {
+ return cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
+ }
+
+ public static Uri getContactPictureUri(Cursor cursor, String id) {
+ Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(id));
+ return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
+ }
+
+ public static InputStream getContactPictureInputStream(ContentResolver cr, String id) {
+ Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(id));
+ return ContactsContract.Contacts.openContactPhotoInputStream(cr, person);
+ }
+
+ public static int getCursorDisplayNameColumnIndex(Cursor cursor) {
+ return cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
+ }
+}
diff --git a/src/org/linphone/compatibility/Compatibility.java b/src/org/linphone/compatibility/Compatibility.java
index ce05a237d..fe1fdea4f 100644
--- a/src/org/linphone/compatibility/Compatibility.java
+++ b/src/org/linphone/compatibility/Compatibility.java
@@ -1,17 +1,102 @@
package org.linphone.compatibility;
+/*
+Compatibility.java
+Copyright (C) 2012 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.
+*/
+import java.io.InputStream;
+import java.util.List;
import org.linphone.mediastream.Version;
-import android.view.Display;
-
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+/**
+ * @author Sylvain Berfini
+ */
public class Compatibility {
-
- public static int getRotation(Display display) {
- if (Version.sdkStrictlyBelow(8)) {
- return API4Compatibility.getRotation(display);
- } else {
- return API8Compatibility.getRotation(display);
+ public static void overridePendingTransition(Activity activity, int idAnimIn, int idAnimOut) {
+ if (Version.sdkAboveOrEqual(5)) {
+ ApiFivePlus.overridePendingTransition(activity, idAnimIn, idAnimOut);
}
}
+ public static Intent prepareAddContactIntent(String displayName, String sipUri) {
+ if (Version.sdkAboveOrEqual(5)) {
+ return ApiFivePlus.prepareAddContactIntent(displayName, sipUri);
+ } else {
+ //TODO
+ }
+ return null;
+ }
+
+ public static List extractContactNumbersAndAddresses(String id, ContentResolver cr) {
+ if (Version.sdkAboveOrEqual(5)) {
+ return ApiFivePlus.extractContactNumbersAndAddresses(id, cr);
+ } else {
+ //TODO
+ }
+ return null;
+ }
+
+ public static Cursor getContactsCursor(ContentResolver cr) {
+ if (Version.sdkAboveOrEqual(5)) {
+ return ApiFivePlus.getContactsCursor(cr);
+ } else {
+ //TODO
+ }
+ return null;
+ }
+
+ public static String getContactDisplayName(Cursor cursor) {
+ if (Version.sdkAboveOrEqual(5)) {
+ return ApiFivePlus.getContactDisplayName(cursor);
+ } else {
+ //TODO
+ }
+ return null;
+ }
+
+ public static Uri getContactPictureUri(Cursor cursor, String id) {
+ if (Version.sdkAboveOrEqual(5)) {
+ return ApiFivePlus.getContactPictureUri(cursor, id);
+ } else {
+ //TODO
+ }
+ return null;
+ }
+
+ public static InputStream getContactPictureInputStream(ContentResolver cr, String id) {
+ if (Version.sdkAboveOrEqual(5)) {
+ return ApiFivePlus.getContactPictureInputStream(cr, id);
+ } else {
+ //TODO
+ }
+ return null;
+ }
+
+ public static int getCursorDisplayNameColumnIndex(Cursor cursor) {
+ if (Version.sdkAboveOrEqual(5)) {
+ return ApiFivePlus.getCursorDisplayNameColumnIndex(cursor);
+ } else {
+ //TODO
+ }
+ return -1;
+ }
}
diff --git a/src/org/linphone/core/LinphoneCallImpl.java b/src/org/linphone/core/LinphoneCallImpl.java
index 27ed253ef..5d886d43e 100644
--- a/src/org/linphone/core/LinphoneCallImpl.java
+++ b/src/org/linphone/core/LinphoneCallImpl.java
@@ -155,7 +155,7 @@ class LinphoneCallImpl implements LinphoneCall {
public float getPlayVolume() {
return getPlayVolume(nativePtr);
}
-
+
private native void takeSnapshot(long nativePtr, String path);
public void takeSnapshot(String path) {
takeSnapshot(nativePtr, path);
diff --git a/src/org/linphone/core/LinphoneCallLogImpl.java b/src/org/linphone/core/LinphoneCallLogImpl.java
index 895e27a38..8972f0a76 100644
--- a/src/org/linphone/core/LinphoneCallLogImpl.java
+++ b/src/org/linphone/core/LinphoneCallLogImpl.java
@@ -26,11 +26,14 @@ class LinphoneCallLogImpl implements LinphoneCallLog {
private native long getFrom(long nativePtr);
private native long getTo(long nativePtr);
private native boolean isIncoming(long nativePtr);
+ private native int getStatus(long nativePtr);
+ private native String getStartDate(long nativePtr);
+ private native int getCallDuration(long nativePtr);
+
LinphoneCallLogImpl(long aNativePtr) {
nativePtr = aNativePtr;
}
-
public CallDirection getDirection() {
return isIncoming(nativePtr)?CallDirection.Incoming:CallDirection.Outgoing;
}
@@ -43,17 +46,18 @@ class LinphoneCallLogImpl implements LinphoneCallLog {
return new LinphoneAddressImpl(getTo(nativePtr));
}
public CallStatus getStatus() {
- throw new RuntimeException("not implemented yet");
- }
- @Override
- public String getStartDate() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public int getCallDuration() {
- // TODO Auto-generated method stub
- return 0;
+ return LinphoneCallLog.CallStatus.fromInt(getStatus(nativePtr));
}
+ public long getNativePtr() {
+ return nativePtr;
+ }
+
+ public String getStartDate() {
+ return getStartDate(nativePtr);
+ }
+
+ public int getCallDuration() {
+ return getCallDuration(nativePtr);
+ }
}
diff --git a/src/org/linphone/core/LinphoneCoreImpl.java b/src/org/linphone/core/LinphoneCoreImpl.java
index 4a962e52e..88084d237 100644
--- a/src/org/linphone/core/LinphoneCoreImpl.java
+++ b/src/org/linphone/core/LinphoneCoreImpl.java
@@ -24,7 +24,6 @@ import java.io.IOException;
class LinphoneCoreImpl implements LinphoneCore {
- @SuppressWarnings("unused")
private final LinphoneCoreListener mListener; //to make sure to keep a reference on this object
private long nativePtr = 0;
private native long newLinphoneCore(LinphoneCoreListener listener,String userConfig,String factoryConfig,Object userdata);
@@ -107,7 +106,9 @@ class LinphoneCoreImpl implements LinphoneCore {
private native void setMediaEncryption(long nativePtr, int menc);
private native boolean isMediaEncryptionMandatory(long nativePtr);
private native void setMediaEncryptionMandatory(long nativePtr, boolean yesno);
-
+ private native void removeCallLog(long nativePtr, long callLogPtr);
+ private native int getMissedCallsCount(long nativePtr);
+ private native void resetMissedCallsCount(long nativePtr);
LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException {
mListener=listener;
@@ -703,28 +704,27 @@ class LinphoneCoreImpl implements LinphoneCore {
{
setCpuCountNative(count);
}
- private native void tunnelSetHttpProxyNative(long nativePtr, String proxy_host, int port, String username, String password);
- @Override
- public void tunnelSetHttpProxy(String proxy_host, int port,
- String username, String password) {
- tunnelSetHttpProxyNative(nativePtr,proxy_host, port, username, password);
- }
-
- private native void removeCallLog(long nativePtr, LinphoneCallLog log);
- public void removeCallLog(LinphoneCallLog log) {
- removeCallLog(nativePtr, log);
- }
-
- private native int getMissedCallsCount(long nativePtr);
+
public int getMissedCallsCount() {
return getMissedCallsCount(nativePtr);
}
+
+ public void removeCallLog(LinphoneCallLog log) {
+ removeCallLog(nativePtr, ((LinphoneCallLogImpl) log).getNativePtr());
+ }
- private native void resetMissedCallsCount(long nativePtr);
public void resetMissedCallsCount() {
resetMissedCallsCount(nativePtr);
}
+ private native void tunnelSetHttpProxy(long nativePtr, String proxy_host, int port,
+ String username, String password);
+ @Override
+ public void tunnelSetHttpProxy(String proxy_host, int port,
+ String username, String password) {
+ tunnelSetHttpProxy(nativePtr, proxy_host, port, username, password);
+ }
+
private native void refreshRegisters(long nativePtr);
public void refreshRegisters() {
refreshRegisters(nativePtr);
diff --git a/src/org/linphone/core/tutorials/AndroidTutorialNotifier.java b/src/org/linphone/core/tutorials/AndroidTutorialNotifier.java
deleted file mode 100644
index 7721f7dc1..000000000
--- a/src/org/linphone/core/tutorials/AndroidTutorialNotifier.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-AndroidTutorialNotifier.java
-Copyright (C) 2010 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.core.tutorials;
-
-import android.os.Handler;
-import android.widget.TextView;
-
-/**
- * Write notifications to a TextView widget.
- * This is an helper class, not a test activity.
- *
- * @author Guillaume Beraudo
- *
- */
-class AndroidTutorialNotifier extends TutorialNotifier {
-
- private Handler mHandler;
- private TextView outputTextView;
-
- public AndroidTutorialNotifier(Handler mHandler, final TextView outputTextView) {
- this.mHandler = mHandler;
- this.outputTextView = outputTextView;
- }
-
-
- @Override
- public void notify(final String s) {
- mHandler.post(new Runnable() {
- public void run() {
- outputTextView.setText(s + "\n" + outputTextView.getText());
- }
- });
- }
-}
diff --git a/src/org/linphone/core/tutorials/TutorialBuddyStatusActivity.java b/src/org/linphone/core/tutorials/TutorialBuddyStatusActivity.java
deleted file mode 100644
index 1bf4f981f..000000000
--- a/src/org/linphone/core/tutorials/TutorialBuddyStatusActivity.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-TutorialBuddyStatusActivity.java
-Copyright (C) 2010 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.core.tutorials;
-
-import org.linphone.R;
-import org.linphone.core.LinphoneCoreException;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Activity for displaying and starting the BuddyStatus example on Android phone.
- *
- * @author Guillaume Beraudo
- *
- */
-public class TutorialBuddyStatusActivity extends Activity {
-
- private static final String defaultSipAddress = "sip:";
- private TextView sipAddressWidget;
- private TextView mySipAddressWidget;
- private TextView mySipPasswordWidget;
-
- private TutorialBuddyStatus tutorial;
- private Handler mHandler = new Handler() ;
- private Button buttonCall;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.hello_world);
- sipAddressWidget = (TextView) findViewById(R.id.AddressId);
- sipAddressWidget.setText(defaultSipAddress);
-
- mySipAddressWidget = (TextView) findViewById(R.id.MyAddressId);
- mySipAddressWidget.setVisibility(View.VISIBLE);
- mySipPasswordWidget = (TextView) findViewById(R.id.Password);
- mySipPasswordWidget.setVisibility(TextView.VISIBLE);
-
-
- // Output text to the outputText widget
- final TextView outputText = (TextView) findViewById(R.id.OutputText);
- final TutorialNotifier notifier = new AndroidTutorialNotifier(mHandler, outputText);
-
-
- // Create BuddyStatus object
- tutorial = new TutorialBuddyStatus(notifier);
-
-
-
- // Assign call action to call button
- buttonCall = (Button) findViewById(R.id.CallButton);
- buttonCall.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- TutorialLaunchingThread thread = new TutorialLaunchingThread();
- buttonCall.setEnabled(false);
- thread.start();
- }
- });
-
- // Assign stop action to stop button
- Button buttonStop = (Button) findViewById(R.id.ButtonStop);
- buttonStop.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- tutorial.stopMainLoop();
- }
- });
- }
-
-
- private class TutorialLaunchingThread extends Thread {
- @Override
- public void run() {
- super.run();
- try {
- String myIdentity = mySipAddressWidget.getText().length()>0?mySipAddressWidget.getText().toString():null;
- String myPassword = mySipPasswordWidget.getText().length()>0?mySipPasswordWidget.getText().toString():null;
- tutorial.launchTutorial(sipAddressWidget.getText().toString(), myIdentity, myPassword);
- mHandler.post(new Runnable() {
- public void run() {
- buttonCall.setEnabled(true);
- }
- });
- } catch (LinphoneCoreException e) {
- e.printStackTrace();
- }
- }
- }
-}
diff --git a/src/org/linphone/core/tutorials/TutorialChatRoomActivity.java b/src/org/linphone/core/tutorials/TutorialChatRoomActivity.java
deleted file mode 100644
index f7dab4ce7..000000000
--- a/src/org/linphone/core/tutorials/TutorialChatRoomActivity.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-TutorialChatRoomActivity.java
-Copyright (C) 2010 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.core.tutorials;
-
-import org.linphone.R;
-import org.linphone.core.LinphoneCoreException;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Activity for displaying and starting the chatroom example on Android phone.
- *
- * @author Guillaume Beraudo
- *
- */
-public class TutorialChatRoomActivity extends Activity {
-
- private static final String defaultSipAddress = "sip:";
- private TextView sipAddressWidget;
- private TutorialChatRoom tutorial;
- private Handler mHandler = new Handler() ;
- private Button buttonCall;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.hello_world);
- sipAddressWidget = (TextView) findViewById(R.id.AddressId);
- sipAddressWidget.setText(defaultSipAddress);
-
- // Output text to the outputText widget
- final TextView outputText = (TextView) findViewById(R.id.OutputText);
- final TutorialNotifier notifier = new AndroidTutorialNotifier(mHandler, outputText);
-
-
- // Create HelloWorld object
- tutorial = new TutorialChatRoom(notifier);
-
-
-
- // Assign call action to call button
- buttonCall = (Button) findViewById(R.id.CallButton);
- buttonCall.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- TutorialLaunchingThread thread = new TutorialLaunchingThread();
- buttonCall.setEnabled(false);
- thread.start();
- }
- });
-
- // Assign stop action to stop button
- Button buttonStop = (Button) findViewById(R.id.ButtonStop);
- buttonStop.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- tutorial.stopMainLoop();
- }
- });
- }
-
-
- private class TutorialLaunchingThread extends Thread {
- @Override
- public void run() {
- super.run();
- try {
- tutorial.launchTutorial(sipAddressWidget.getText().toString());
- mHandler.post(new Runnable() {
- public void run() {
- buttonCall.setEnabled(true);
- }
- });
- } catch (LinphoneCoreException e) {
- e.printStackTrace();
- }
- }
- }
-}
diff --git a/src/org/linphone/core/tutorials/TutorialHelloWorldActivity.java b/src/org/linphone/core/tutorials/TutorialHelloWorldActivity.java
deleted file mode 100644
index 60bd872c7..000000000
--- a/src/org/linphone/core/tutorials/TutorialHelloWorldActivity.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-TutorialHelloWorldActivity.java
-Copyright (C) 2010 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.core.tutorials;
-
-import org.linphone.R;
-import org.linphone.core.LinphoneCoreException;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Activity for displaying and starting the HelloWorld example on Android phone.
- *
- * @author Guillaume Beraudo
- *
- */
-public class TutorialHelloWorldActivity extends Activity {
-
- private static final String defaultSipAddress = "sip:";
- private TextView sipAddressWidget;
- private TutorialHelloWorld tutorial;
- private Handler mHandler = new Handler() ;
- private Button buttonCall;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.hello_world);
- sipAddressWidget = (TextView) findViewById(R.id.AddressId);
- sipAddressWidget.setText(defaultSipAddress);
-
- // Output text to the outputText widget
- final TextView outputText = (TextView) findViewById(R.id.OutputText);
- final TutorialNotifier notifier = new AndroidTutorialNotifier(mHandler, outputText);
-
-
- // Create HelloWorld object
- tutorial = new TutorialHelloWorld(notifier);
-
-
-
- // Assign call action to call button
- buttonCall = (Button) findViewById(R.id.CallButton);
- buttonCall.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- TutorialLaunchingThread thread = new TutorialLaunchingThread();
- buttonCall.setEnabled(false);
- thread.start();
- }
- });
-
- // Assign stop action to stop button
- Button buttonStop = (Button) findViewById(R.id.ButtonStop);
- buttonStop.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- tutorial.stopMainLoop();
- }
- });
- }
-
-
- private class TutorialLaunchingThread extends Thread {
- @Override
- public void run() {
- super.run();
- try {
- tutorial.launchTutorial(sipAddressWidget.getText().toString());
- mHandler.post(new Runnable() {
- public void run() {
- buttonCall.setEnabled(true);
- }
- });
- } catch (LinphoneCoreException e) {
- e.printStackTrace();
- }
- }
- }
-}
diff --git a/src/org/linphone/core/tutorials/TutorialRegistrationActivity.java b/src/org/linphone/core/tutorials/TutorialRegistrationActivity.java
deleted file mode 100644
index 94670480c..000000000
--- a/src/org/linphone/core/tutorials/TutorialRegistrationActivity.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-TutorialRegistrationActivity.java
-Copyright (C) 2010 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.core.tutorials;
-
-import org.linphone.R;
-import org.linphone.core.LinphoneCoreException;
-
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Activity for displaying and starting the registration example on Android phone.
- *
- * @author Guillaume Beraudo
- *
- */
-public class TutorialRegistrationActivity extends TutorialHelloWorldActivity {
-
- private static final String defaultSipAddress = "sip:";
- private static final String defaultSipPassword = "";
- private TextView sipAddressWidget;
- private TextView sipPasswordWidget;
- private TutorialRegistration tutorial;
- private Button buttonCall;
- private Handler mHandler = new Handler();
- private TextView outputText;
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.hello_world);
- sipAddressWidget = (TextView) findViewById(R.id.AddressId);
- sipAddressWidget.setText(defaultSipAddress);
- sipPasswordWidget = (TextView) findViewById(R.id.Password);
- sipPasswordWidget.setVisibility(TextView.VISIBLE);
- sipPasswordWidget.setText(defaultSipPassword);
-
- // Output text to the outputText widget
- outputText = (TextView) findViewById(R.id.OutputText);
- final TutorialNotifier notifier = new AndroidTutorialNotifier(mHandler, outputText);
-
-
- // Create Tutorial object
- tutorial = new TutorialRegistration(notifier);
-
-
-
- // Assign call action to call button
- buttonCall = (Button) findViewById(R.id.CallButton);
- buttonCall.setText("Register");
- buttonCall.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- TutorialLaunchingThread thread = new TutorialLaunchingThread();
- buttonCall.setEnabled(false);
- thread.start();
- }
- });
-
-
- Button buttonStop = (Button) findViewById(R.id.ButtonStop);
- buttonStop.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- tutorial.stopMainLoop();
- }
- });
- }
-
-
- private class TutorialLaunchingThread extends Thread {
- @Override
- public void run() {
- super.run();
- try {
- tutorial.launchTutorial(
- sipAddressWidget.getText().toString(),
- sipPasswordWidget.getText().toString());
- } catch (LinphoneCoreException e) {
- e.printStackTrace();
- outputText.setText(e.getMessage() +"\n"+outputText.getText());
- }
- }
- }
-}
diff --git a/src/org/linphone/setup/GenericLoginFragment.java b/src/org/linphone/setup/GenericLoginFragment.java
new file mode 100644
index 000000000..216d389a0
--- /dev/null
+++ b/src/org/linphone/setup/GenericLoginFragment.java
@@ -0,0 +1,65 @@
+package org.linphone.setup;
+/*
+GenericLoginFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.R;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.Toast;
+/**
+ * @author Sylvain Berfini
+ */
+public class GenericLoginFragment extends Fragment implements OnClickListener {
+ private EditText login, password, domain;
+ private ImageView apply;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.setup_generic_login, container, false);
+
+ login = (EditText) view.findViewById(R.id.setup_username);
+ password = (EditText) view.findViewById(R.id.setup_password);
+ domain = (EditText) view.findViewById(R.id.setup_domain);
+ apply = (ImageView) view.findViewById(R.id.setup_apply);
+ apply.setOnClickListener(this);
+
+ return view;
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (id == R.id.setup_apply) {
+ if (login.getText() == null || login.length() == 0 || password.getText() == null || password.length() == 0 || domain.getText() == null || domain.length() == 0) {
+ Toast.makeText(getActivity(), getString(R.string.first_launch_no_login_password), Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ SetupActivity.instance().logIn(login.getText().toString(), password.getText().toString(), domain.getText().toString());
+ }
+ }
+}
diff --git a/src/org/linphone/setup/LinphoneLoginFragment.java b/src/org/linphone/setup/LinphoneLoginFragment.java
new file mode 100644
index 000000000..91e5fcf73
--- /dev/null
+++ b/src/org/linphone/setup/LinphoneLoginFragment.java
@@ -0,0 +1,64 @@
+package org.linphone.setup;
+/*
+LinphoneLoginFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.R;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.Toast;
+/**
+ * @author Sylvain Berfini
+ */
+public class LinphoneLoginFragment extends Fragment implements OnClickListener {
+ private EditText login, password;
+ private ImageView apply;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.setup_linphone_login, container, false);
+
+ login = (EditText) view.findViewById(R.id.setup_username);
+ password = (EditText) view.findViewById(R.id.setup_password);
+ apply = (ImageView) view.findViewById(R.id.setup_apply);
+ apply.setOnClickListener(this);
+
+ return view;
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (id == R.id.setup_apply) {
+ if (login.getText() == null || login.length() == 0 || password.getText() == null || password.length() == 0) {
+ Toast.makeText(getActivity(), getString(R.string.first_launch_no_login_password), Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ SetupActivity.instance().logIn(login.getText().toString(), password.getText().toString(), getString(R.string.default_domain));
+ }
+ }
+}
diff --git a/src/org/linphone/setup/MenuFragment.java b/src/org/linphone/setup/MenuFragment.java
new file mode 100644
index 000000000..704aa580c
--- /dev/null
+++ b/src/org/linphone/setup/MenuFragment.java
@@ -0,0 +1,64 @@
+package org.linphone.setup;
+/*
+MenuFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.R;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+/**
+ * @author Sylvain Berfini
+ */
+public class MenuFragment extends Fragment implements OnClickListener {
+ private ImageView createAccount, logLinphoneAccount, logGenericAccount;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.setup_menu, container, false);
+
+ createAccount = (ImageView) view.findViewById(R.id.setup_create_account);
+ createAccount.setOnClickListener(this);
+
+ logLinphoneAccount = (ImageView) view.findViewById(R.id.setup_login_linphone);
+ logLinphoneAccount.setOnClickListener(this);
+
+ logGenericAccount = (ImageView) view.findViewById(R.id.setup_login_generic);
+ logGenericAccount.setOnClickListener(this);
+
+ return view;
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (id == R.id.setup_login_generic) {
+ SetupActivity.instance().displayLoginGeneric();
+ } else if (id == R.id.setup_login_linphone) {
+ SetupActivity.instance().displayLoginLinphone();
+ } else if (id == R.id.setup_create_account) {
+ SetupActivity.instance().displayWizard();
+ }
+ }
+}
diff --git a/src/org/linphone/setup/SetupActivity.java b/src/org/linphone/setup/SetupActivity.java
new file mode 100644
index 000000000..0a7cc7d8e
--- /dev/null
+++ b/src/org/linphone/setup/SetupActivity.java
@@ -0,0 +1,224 @@
+package org.linphone.setup;
+/*
+SetupActivity.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.LinphoneManager;
+import org.linphone.R;
+import org.linphone.core.Log;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.ImageView;
+import android.widget.Toast;
+/**
+ * @author Sylvain Berfini
+ */
+public class SetupActivity extends FragmentActivity implements OnClickListener {
+ private static SetupActivity instance;
+ private ImageView back, next, cancel;
+ private SetupFragments currentFragment;
+ private SharedPreferences mPref;
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.setup);
+
+ if (findViewById(R.id.fragmentContainer) != null) {
+ if (savedInstanceState != null) {
+ return;
+ }
+
+ WelcomeFragment welcomeFragment = new WelcomeFragment();
+ getSupportFragmentManager().beginTransaction().add(R.id.fragmentContainer, welcomeFragment).commit();
+
+ currentFragment = SetupFragments.WELCOME;
+ }
+
+ mPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+
+ initUI();
+ instance = this;
+ };
+
+ public static SetupActivity instance() {
+ return instance;
+ }
+
+ private void initUI() {
+ back = (ImageView) findViewById(R.id.setup_back);
+ back.setOnClickListener(this);
+ next = (ImageView) findViewById(R.id.setup_next);
+ next.setOnClickListener(this);
+ cancel = (ImageView) findViewById(R.id.setup_cancel);
+ cancel.setOnClickListener(this);
+ }
+
+ private void changeFragment(Fragment newFragment) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+
+// transaction.addToBackStack("");
+ transaction.replace(R.id.fragmentContainer, newFragment);
+
+ transaction.commitAllowingStateLoss();
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+
+ if (id == R.id.setup_cancel) {
+ finish();
+ } else if (id == R.id.setup_next) {
+ if (currentFragment == SetupFragments.WELCOME) {
+ MenuFragment fragment = new MenuFragment();
+ changeFragment(fragment);
+ currentFragment = SetupFragments.MENU;
+
+ next.setVisibility(View.GONE);
+ back.setVisibility(View.VISIBLE);
+ } else if (currentFragment == SetupFragments.WIZARD_CONFIRM) {
+ finish();
+ }
+ } else if (id == R.id.setup_back) {
+ handleBackEvent();
+ }
+ }
+
+ private void handleBackEvent() {
+ if (currentFragment == SetupFragments.MENU) {
+ WelcomeFragment fragment = new WelcomeFragment();
+ changeFragment(fragment);
+ currentFragment = SetupFragments.WELCOME;
+
+ next.setVisibility(View.VISIBLE);
+ back.setVisibility(View.GONE);
+ } else if (currentFragment == SetupFragments.GENERIC_LOGIN || currentFragment == SetupFragments.LINPHONE_LOGIN || currentFragment == SetupFragments.WIZARD) {
+ MenuFragment fragment = new MenuFragment();
+ changeFragment(fragment);
+ currentFragment = SetupFragments.MENU;
+ } else if (currentFragment == SetupFragments.WELCOME) {
+ finish();
+ }
+ }
+
+ public void logIn(String username, String password, String domain) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
+
+ saveCreatedAccount(username, password, domain);
+ LinphoneManager.getInstance().initializePayloads();
+
+ try {
+ LinphoneManager.getInstance().initFromConf();
+ } catch (Throwable e) {
+ Log.e(e, "Error while initializing from config in first login activity");
+ Toast.makeText(this, getString(R.string.error), Toast.LENGTH_LONG).show();
+ }
+
+ if (LinphoneManager.getLc().getDefaultProxyConfig() != null) {
+ writePreference(R.string.first_launch_suceeded_once_key, true);
+ finish();
+ }
+ }
+
+ private void writePreference(int key, String value) {
+ mPref.edit().putString(getString(key), value).commit();
+ }
+
+ private void writePreference(String key, String value) {
+ mPref.edit().putString(key, value).commit();
+ }
+
+ private void writePreference(int key, int value) {
+ mPref.edit().putInt(getString(key), value).commit();
+ }
+
+ private void writePreference(int key, boolean value) {
+ mPref.edit().putBoolean(getString(key), value).commit();
+ }
+
+ public void displayLoginGeneric() {
+ GenericLoginFragment fragment = new GenericLoginFragment();
+ changeFragment(fragment);
+ currentFragment = SetupFragments.GENERIC_LOGIN;
+ }
+
+ public void displayLoginLinphone() {
+ LinphoneLoginFragment fragment = new LinphoneLoginFragment();
+ changeFragment(fragment);
+ currentFragment = SetupFragments.LINPHONE_LOGIN;
+ }
+
+ public void displayWizard() {
+ WizardFragment fragment = new WizardFragment();
+ changeFragment(fragment);
+ currentFragment = SetupFragments.WIZARD;
+ }
+
+ public void saveCreatedAccount(String username, String password, String domain) {
+ int newAccountId = mPref.getInt(getString(R.string.pref_extra_accounts), 0);
+ writePreference(R.string.pref_extra_accounts, newAccountId+1);
+
+ if (newAccountId == 0) {
+ writePreference(R.string.pref_username_key, username);
+ writePreference(R.string.pref_passwd_key, password);
+ writePreference(R.string.pref_domain_key, domain);
+ } else {
+ writePreference(getString(R.string.pref_username_key) + newAccountId, username);
+ writePreference(getString(R.string.pref_passwd_key) + newAccountId, password);
+ writePreference(getString(R.string.pref_domain_key) + newAccountId, domain);
+ }
+ }
+
+ public void displayWizardConfirm(String username) {
+ WizardConfirmFragment fragment = new WizardConfirmFragment();
+
+ Bundle extras = new Bundle();
+ extras.putString("Username", username);
+ fragment.setArguments(extras);
+ changeFragment(fragment);
+
+ currentFragment = SetupFragments.WIZARD_CONFIRM;
+
+ next.setVisibility(View.VISIBLE);
+ next.setEnabled(false);
+ back.setVisibility(View.GONE);
+ }
+
+ public void isAccountVerified() {
+ next.setEnabled(true);
+ Toast.makeText(this, getString(R.string.setup_account_validated), Toast.LENGTH_LONG).show();
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ handleBackEvent();
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+}
diff --git a/src/org/linphone/setup/SetupFragments.java b/src/org/linphone/setup/SetupFragments.java
new file mode 100644
index 000000000..966ab5863
--- /dev/null
+++ b/src/org/linphone/setup/SetupFragments.java
@@ -0,0 +1,30 @@
+package org.linphone.setup;
+/*
+SetupFragments.java
+Copyright (C) 2012 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.
+*/
+/**
+ * @author Sylvain Berfini
+ */
+public enum SetupFragments {
+ WELCOME,
+ MENU,
+ WIZARD,
+ WIZARD_CONFIRM,
+ LINPHONE_LOGIN,
+ GENERIC_LOGIN;
+}
diff --git a/src/org/linphone/setup/WelcomeFragment.java b/src/org/linphone/setup/WelcomeFragment.java
new file mode 100644
index 000000000..48d330731
--- /dev/null
+++ b/src/org/linphone/setup/WelcomeFragment.java
@@ -0,0 +1,38 @@
+package org.linphone.setup;
+/*
+WelcomeFragment.java
+Copyright (C) 2012 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.
+*/
+import org.linphone.R;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+/**
+ * @author Sylvain Berfini
+ */
+public class WelcomeFragment extends Fragment {
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.setup_welcome, container, false);
+
+ return view;
+ }
+}
diff --git a/src/org/linphone/setup/WizardConfirmFragment.java b/src/org/linphone/setup/WizardConfirmFragment.java
new file mode 100644
index 000000000..66f2a1434
--- /dev/null
+++ b/src/org/linphone/setup/WizardConfirmFragment.java
@@ -0,0 +1,109 @@
+package org.linphone.setup;
+/*
+WizardConfirmFragment.java
+Copyright (C) 2012 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.
+*/
+import java.net.URL;
+
+import org.linphone.R;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.Toast;
+import de.timroes.axmlrpc.XMLRPCCallback;
+import de.timroes.axmlrpc.XMLRPCClient;
+import de.timroes.axmlrpc.XMLRPCException;
+import de.timroes.axmlrpc.XMLRPCServerException;
+/**
+ * @author Sylvain Berfini
+ */
+public class WizardConfirmFragment extends Fragment {
+ private String username;
+ private Handler mHandler = new Handler();
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.setup_wizard_confirm, container, false);
+
+ username = getArguments().getString("Username");
+
+ ImageView checkAccount = (ImageView) view.findViewById(R.id.setup_check);
+ checkAccount.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ isAccountVerified(username);
+ }
+ });
+
+ return view;
+ }
+
+ private void isAccountVerified(String username) {
+ final Runnable runNotReachable = new Runnable() {
+ public void run() {
+ Toast.makeText(getActivity(), getString(R.string.wizard_server_unavailable), Toast.LENGTH_LONG);
+ }
+ };
+
+ try {
+ XMLRPCClient client = new XMLRPCClient(new URL(getString(R.string.wizard_url)));
+
+ XMLRPCCallback listener = new XMLRPCCallback() {
+ Runnable runNotOk = new Runnable() {
+ public void run() {
+ Toast.makeText(getActivity(), getString(R.string.setup_account_not_validated), Toast.LENGTH_LONG).show();
+ }
+ };
+
+ Runnable runOk = new Runnable() {
+ public void run() {
+ SetupActivity.instance().isAccountVerified();
+ }
+ };
+
+ public void onResponse(long id, Object result) {
+ int answer = (Integer) result;
+ if (answer != 1) {
+ mHandler.post(runNotOk);
+ } else {
+ mHandler.post(runOk);
+ }
+ }
+
+ public void onError(long id, XMLRPCException error) {
+ mHandler.post(runNotReachable);
+ }
+
+ public void onServerError(long id, XMLRPCServerException error) {
+ mHandler.post(runNotReachable);
+ }
+ };
+
+ client.callAsync(listener, "check_account_validated", "sip:" + username + "@" + getString(R.string.default_domain));
+ }
+ catch(Exception ex) {
+ mHandler.post(runNotReachable);
+ }
+ }
+}
diff --git a/src/org/linphone/setup/WizardFragment.java b/src/org/linphone/setup/WizardFragment.java
new file mode 100644
index 000000000..0989bc21e
--- /dev/null
+++ b/src/org/linphone/setup/WizardFragment.java
@@ -0,0 +1,290 @@
+package org.linphone.setup;
+/*
+WizardFragment.java
+Copyright (C) 2012 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.
+*/
+import java.net.URL;
+
+import org.linphone.R;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.timroes.axmlrpc.XMLRPCCallback;
+import de.timroes.axmlrpc.XMLRPCClient;
+import de.timroes.axmlrpc.XMLRPCException;
+import de.timroes.axmlrpc.XMLRPCServerException;
+/**
+ * @author Sylvain Berfini
+ */
+public class WizardFragment extends Fragment {
+ private Handler mHandler = new Handler();
+ private EditText username, password, passwordConfirm, email;
+
+ private boolean usernameOk = false;
+ private boolean passwordOk = false;
+ private boolean emailOk = false;
+ private ImageView createAccount;
+ private TextView errorMessage;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.setup_wizard, container, false);
+
+ username = (EditText) view.findViewById(R.id.setup_username);
+ ImageView usernameOkIV = (ImageView) view.findViewById(R.id.setup_username_ok);
+ addXMLRPCUsernameHandler(username, usernameOkIV);
+
+ password = (EditText) view.findViewById(R.id.setup_password);
+ passwordConfirm = (EditText) view.findViewById(R.id.setup_password_confirm);
+
+ ImageView passwordOkIV = (ImageView) view.findViewById(R.id.setup_password_ok);
+ addXMLRPCPasswordHandler(password, passwordConfirm, passwordOkIV);
+
+ email = (EditText) view.findViewById(R.id.setup_email);
+ ImageView emailOkIV = (ImageView) view.findViewById(R.id.setup_email_ok);
+ addXMLRPCEmailHandler(email, emailOkIV);
+
+ errorMessage = (TextView) view.findViewById(R.id.setup_error);
+
+ createAccount = (ImageView) view.findViewById(R.id.setup_create);
+ createAccount.setEnabled(false);
+ createAccount.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ createAccount(username.getText().toString(), password.getText().toString(), email.getText().toString(), false);
+ }
+ });
+
+ return view;
+ }
+
+ private boolean isUsernameCorrect(String username) {
+ return username.matches("^[a-zA-Z]+[a-zA-Z0-9.\\-_]{2,}$");
+ }
+
+ private void isUsernameRegistred(String username, final ImageView icon) {
+ final Runnable runNotReachable = new Runnable() {
+ public void run() {
+ errorMessage.setText(R.string.wizard_server_unavailable);
+ usernameOk = false;
+ icon.setImageResource(R.drawable.wizard_notok);
+ createAccount.setEnabled(usernameOk && passwordOk && emailOk);
+ }
+ };
+
+ try {
+ XMLRPCClient client = new XMLRPCClient(new URL(getString(R.string.wizard_url)));
+
+ XMLRPCCallback listener = new XMLRPCCallback() {
+ Runnable runNotOk = new Runnable() {
+ public void run() {
+ errorMessage.setText(R.string.wizard_username_unavailable);
+ usernameOk = false;
+ icon.setImageResource(R.drawable.wizard_notok);
+ createAccount.setEnabled(usernameOk && passwordOk && emailOk);
+ }
+ };
+
+ Runnable runOk = new Runnable() {
+ public void run() {
+ errorMessage.setText("");
+ icon.setImageResource(R.drawable.wizard_ok);
+ usernameOk = true;
+ createAccount.setEnabled(usernameOk && passwordOk && emailOk);
+ }
+ };
+
+ public void onResponse(long id, Object result) {
+ int answer = (Integer) result;
+ if (answer != 0) {
+ mHandler.post(runNotOk);
+ }
+ else {
+ mHandler.post(runOk);
+ }
+ }
+
+ public void onError(long id, XMLRPCException error) {
+ mHandler.post(runNotReachable);
+ }
+
+ public void onServerError(long id, XMLRPCServerException error) {
+ mHandler.post(runNotReachable);
+ }
+ };
+
+ client.callAsync(listener, "check_account", username);
+ }
+ catch(Exception ex) {
+ mHandler.post(runNotReachable);
+ }
+ }
+
+ private boolean isEmailCorrect(String email) {
+ return email.matches("^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\\.-][a-z0-9]+)*)+\\.[a-z]{2,}$");
+ }
+
+ private boolean isPasswordCorrect(String password) {
+ return password.length() >= 6;
+ }
+
+ private void createAccount(final String username, final String password, String email, boolean suscribe) {
+ final Runnable runNotReachable = new Runnable() {
+ public void run() {
+ errorMessage.setText(R.string.wizard_server_unavailable);
+ }
+ };
+
+ try {
+ XMLRPCClient client = new XMLRPCClient(new URL(getString(R.string.wizard_url)));
+
+ XMLRPCCallback listener = new XMLRPCCallback() {
+ Runnable runNotOk = new Runnable() {
+ public void run() {
+ errorMessage.setText(R.string.wizard_failed);
+ }
+ };
+
+ Runnable runOk = new Runnable() {
+ public void run() {
+ SetupActivity.instance().saveCreatedAccount(username, password, getString(R.string.default_domain));
+ SetupActivity.instance().displayWizardConfirm(username);
+ }
+ };
+
+ public void onResponse(long id, Object result) {
+ int answer = (Integer) result;
+ if (answer != 0) {
+ mHandler.post(runNotOk);
+ } else {
+ mHandler.post(runOk);
+ }
+ }
+
+ public void onError(long id, XMLRPCException error) {
+ mHandler.post(runNotReachable);
+ }
+
+ public void onServerError(long id, XMLRPCServerException error) {
+ mHandler.post(runNotReachable);
+ }
+ };
+
+ client.callAsync(listener, "create_account_with_useragent", username, password, email, "linphone-wizard-android");
+ }
+ catch(Exception ex) {
+ mHandler.post(runNotReachable);
+ }
+ }
+
+ private void addXMLRPCUsernameHandler(final EditText field, final ImageView icon) {
+ field.addTextChangedListener(new TextWatcher() {
+ public void afterTextChanged(Editable arg0) {
+
+ }
+
+ public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+
+ }
+
+ public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
+ {
+ usernameOk = false;
+ if (isUsernameCorrect(field.getText().toString()))
+ {
+ isUsernameRegistred(field.getText().toString(), icon);
+ }
+ else {
+ errorMessage.setText(R.string.wizard_username_incorrect);
+ icon.setImageResource(R.drawable.wizard_notok);
+ }
+ }
+ });
+ }
+
+ private void addXMLRPCEmailHandler(final EditText field, final ImageView icon) {
+ field.addTextChangedListener(new TextWatcher() {
+ public void afterTextChanged(Editable arg0) {
+
+ }
+
+ public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+
+ }
+
+ public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
+ {
+ emailOk = false;
+ if (isEmailCorrect(field.getText().toString())) {
+ icon.setImageResource(R.drawable.wizard_ok);
+ emailOk = true;
+ errorMessage.setText("");
+ }
+ else {
+ errorMessage.setText(R.string.wizard_email_incorrect);
+ icon.setImageResource(R.drawable.wizard_notok);
+ }
+ createAccount.setEnabled(usernameOk && passwordOk && emailOk);
+ }
+ });
+ }
+
+ private void addXMLRPCPasswordHandler(final EditText field1, final EditText field2, final ImageView icon) {
+ TextWatcher passwordListener = new TextWatcher() {
+ public void afterTextChanged(Editable arg0) {
+
+ }
+
+ public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+
+ }
+
+ public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
+ {
+ passwordOk = false;
+ if (isPasswordCorrect(field1.getText().toString()) && field1.getText().toString().equals(field2.getText().toString())) {
+ passwordOk = true;
+ icon.setImageResource(R.drawable.wizard_ok);
+ errorMessage.setText("");
+ }
+ else {
+ if (isPasswordCorrect(field1.getText().toString())) {
+ errorMessage.setText(R.string.wizard_passwords_unmatched);
+ }
+ else {
+ errorMessage.setText(R.string.wizard_password_incorrect);
+ }
+ icon.setImageResource(R.drawable.wizard_notok);
+ }
+ createAccount.setEnabled(usernameOk && passwordOk && emailOk);
+ }
+ };
+
+ field1.addTextChangedListener(passwordListener);
+ field2.addTextChangedListener(passwordListener);
+ }
+}
diff --git a/src/org/linphone/ui/AddVideoButton.java b/src/org/linphone/ui/AddVideoButton.java
deleted file mode 100644
index 47d6a1ed9..000000000
--- a/src/org/linphone/ui/AddVideoButton.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-AddVideoButton.java
-Copyright (C) 2010 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.ui;
-
-import org.linphone.LinphoneActivity;
-import org.linphone.LinphoneManager;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ImageButton;
-
-/**
- * @author Guillaume Beraudo
- *
- */
-public class AddVideoButton extends ImageButton implements OnClickListener {
-
- public AddVideoButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- setOnClickListener(this);
- }
-
- public void onClick(View v) {
- if (!LinphoneManager.getInstance().addVideo()) {
- LinphoneActivity.instance().startVideoActivity(LinphoneManager.getLc().getCurrentCall(), 0);
- }
- }
-}
diff --git a/src/org/linphone/ui/AddressText.java b/src/org/linphone/ui/AddressText.java
index 5f151326c..4ea908130 100644
--- a/src/org/linphone/ui/AddressText.java
+++ b/src/org/linphone/ui/AddressText.java
@@ -62,7 +62,7 @@ public class AddressText extends EditText implements AddressType {
protected void onTextChanged(CharSequence text, int start, int before,
int after) {
clearDisplayedName();
- pictureUri=null;
+ pictureUri = null;
super.onTextChanged(text, start, before, after);
}
diff --git a/src/org/linphone/ui/BubbleChat.java b/src/org/linphone/ui/BubbleChat.java
new file mode 100644
index 000000000..89dd2996b
--- /dev/null
+++ b/src/org/linphone/ui/BubbleChat.java
@@ -0,0 +1,119 @@
+package org.linphone.ui;
+/*
+BubbleChat.java
+Copyright (C) 2012 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.
+*/
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import org.linphone.R;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.RelativeLayout;
+import android.widget.RelativeLayout.LayoutParams;
+import android.widget.TextView;
+
+/**
+ * @author Sylvain Berfini
+ */
+public class BubbleChat {
+ private RelativeLayout view;
+
+ public BubbleChat(Context context, int id, String message, String time, boolean isIncoming, int previousID) {
+ view = new RelativeLayout(context);
+
+ LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+
+ if (isIncoming) {
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+ view.setBackgroundResource(R.drawable.chat_bubble_incoming);
+ }
+ else {
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+ view.setBackgroundResource(R.drawable.chat_bubble_outgoing);
+ }
+
+ if (previousID != -1) {
+ layoutParams.addRule(RelativeLayout.BELOW, previousID);
+ }
+
+ TextView messageView = new TextView(context);
+ messageView.setId(id);
+ messageView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+ messageView.setText(message);
+ messageView.setTextColor(Color.BLACK);
+
+ view.setId(id);
+ layoutParams.setMargins(0, pixelsToDpi(context, 10), 0, 0);
+ view.setLayoutParams(layoutParams);
+ view.addView(messageView);
+
+ if (context.getResources().getBoolean(R.bool.display_messages_time)) {
+ TextView timeView = new TextView(context);
+ LayoutParams timeParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ timeParams.addRule(RelativeLayout.BELOW, id);
+ timeView.setLayoutParams(timeParams);
+ timeView.setText(timestampToHumanDate(context, time));
+ timeView.setTextColor(Color.GRAY);
+ timeView.setTextSize(12);
+ view.addView(timeView);
+ }
+ }
+
+ public View getView() {
+ return view;
+ }
+
+ private String timestampToHumanDate(Context context, String timestamp) {
+ try {
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(Long.parseLong(timestamp));
+
+ SimpleDateFormat dateFormat;
+ if (isToday(cal)) {
+ dateFormat = new SimpleDateFormat(context.getResources().getString(R.string.today_date_format));
+ } else {
+ dateFormat = new SimpleDateFormat(context.getResources().getString(R.string.messages_date_format));
+ }
+
+ return dateFormat.format(cal.getTime());
+ } catch (NumberFormatException nfe) {
+ return timestamp;
+ }
+ }
+
+ private boolean isToday(Calendar cal) {
+ return isSameDay(cal, Calendar.getInstance());
+ }
+
+ private boolean isSameDay(Calendar cal1, Calendar cal2) {
+ if (cal1 == null || cal2 == null) {
+ return false;
+ }
+
+ return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
+ cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
+ cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
+ }
+
+ private int pixelsToDpi(Context context, int pixels) {
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, (float) pixels, context.getResources().getDisplayMetrics());
+ }
+}
diff --git a/src/org/linphone/ui/CallButton.java b/src/org/linphone/ui/CallButton.java
index f0223f0f7..9acbb74eb 100644
--- a/src/org/linphone/ui/CallButton.java
+++ b/src/org/linphone/ui/CallButton.java
@@ -26,14 +26,13 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.Toast;
/**
* @author Guillaume Beraudo
- *
*/
-public class CallButton extends ImageButton implements OnClickListener, AddressAware {
+public class CallButton extends ImageView implements OnClickListener, AddressAware {
private AddressText mAddress;
public void setAddressWidget(AddressText a) {mAddress = a;}
@@ -49,7 +48,7 @@ public class CallButton extends ImageButton implements OnClickListener, AddressA
public void onClick(View v) {
try {
if (!LinphoneManager.getInstance().acceptCallIfIncomingPending()) {
- if (mAddress.getText().length() >0) {
+ if (mAddress.getText().length() > 0) {
LinphoneManager.getInstance().newOutgoingCall(mAddress);
}
}
diff --git a/src/org/linphone/ui/CameraView.java b/src/org/linphone/ui/CameraView.java
deleted file mode 100644
index 2f2f5b781..000000000
--- a/src/org/linphone/ui/CameraView.java
+++ /dev/null
@@ -1,195 +0,0 @@
-package org.linphone.ui;
-
-import java.io.IOException;
-import java.util.List;
-
-import android.content.Context;
-import android.hardware.Camera;
-import android.hardware.Camera.CameraInfo;
-import android.hardware.Camera.Size;
-import android.util.AttributeSet;
-import android.view.Display;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-
-public class CameraView extends ViewGroup implements SurfaceHolder.Callback {
-
- public CameraView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mSurfaceView = new SurfaceView(context);
- addView(mSurfaceView);
-
- mHolder = mSurfaceView.getHolder();
- mHolder.addCallback(this);
- mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- }
-
- CameraView(Context context) {
- super(context);
-
- mSurfaceView = new SurfaceView(context);
- addView(mSurfaceView);
-
- mHolder = mSurfaceView.getHolder();
- mHolder.addCallback(this);
- mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- }
-
- SurfaceView mSurfaceView;
- SurfaceHolder mHolder;
- Size mPreviewSize;
- List mSupportedSizes;
- Camera mCamera;
- int mCameraId;
-
- public void setCamera(Camera camera, int id) {
- mCamera = camera;
- mCameraId = id;
- if (mCamera != null) {
- mSupportedSizes = mCamera.getParameters().getSupportedPreviewSizes();
- requestLayout();
- }
- }
-
- public void switchCamera(Camera camera, int id) {
- setCamera(camera, id);
- try {
- camera.setPreviewDisplay(mHolder);
- } catch (IOException exception) {
-
- }
- Camera.Parameters parameters = camera.getParameters();
- parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
- requestLayout();
-
- camera.setParameters(parameters);
- }
-
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);;
- int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);;
- setMeasuredDimension(width, height);
-
- if (mSupportedSizes != null) {
- mPreviewSize = getOptimalPreviewSize(mSupportedSizes, width, height);
- }
-
- Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
- if (display.getRotation() == Surface.ROTATION_90 || display.getRotation() == Surface.ROTATION_270) {
- Size tempSize = mPreviewSize;
- mPreviewSize.width = tempSize.height;
- mPreviewSize.height = tempSize.width;
- }
- }
-
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- if (changed && getChildCount() > 0) {
- final View child = getChildAt(0);
-
- final int width = r - l;
- final int height = b - t;
-
- int previewWidth = width;
- int previewHeight = height;
- if (mPreviewSize != null) {
- previewWidth = mPreviewSize.width;
- previewHeight = mPreviewSize.height;
- }
-
- // Center the surface view
- if (width * previewHeight > height * previewWidth) {
- final int scaledChildWidth = previewWidth * height / previewHeight;
- child.layout((width - scaledChildWidth) / 2, 0,
- (width + scaledChildWidth) / 2, height);
- } else {
- final int scaledChildHeight = previewHeight * width / previewWidth;
- child.layout(0, (height - scaledChildHeight) / 2,
- width, (height + scaledChildHeight) / 2);
- }
- }
- }
-
- public void surfaceCreated(SurfaceHolder holder) {
- try {
- if (mCamera != null) {
- mCamera.setPreviewDisplay(holder);
- }
- } catch (IOException exception) {
-
- }
- }
-
- public void surfaceDestroyed(SurfaceHolder holder) {
- if (mCamera != null) {
- mCamera.stopPreview();
- }
- }
-
- private Size getOptimalPreviewSize(List sizes, int w, int h) {
- final double ASPECT_TOLERANCE = 0.1;
- double targetRatio = (double) w / h;
- if (sizes == null) return null;
-
- Size optimalSize = null;
- double minDiff = Double.MAX_VALUE;
-
- int targetHeight = h;
-
- for (Size size : sizes) {
- double ratio = (double) size.width / size.height;
- if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
- if (Math.abs(size.height - targetHeight) < minDiff) {
- optimalSize = size;
- minDiff = Math.abs(size.height - targetHeight);
- }
- }
-
- if (optimalSize == null) {
- minDiff = Double.MAX_VALUE;
- for (Size size : sizes) {
- if (Math.abs(size.height - targetHeight) < minDiff) {
- optimalSize = size;
- minDiff = Math.abs(size.height - targetHeight);
- }
- }
- }
- return optimalSize;
- }
-
- public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
- if (mCamera == null)
- return;
-
- mCamera.stopPreview();
- Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
- Camera.Parameters parameters = mCamera.getParameters();
-
- int rotation = 0;
- if(display.getRotation() == Surface.ROTATION_90) {
- rotation = 90;
- }
- else if(display.getRotation() == Surface.ROTATION_270) {
- rotation = 270;
- }
- else if (display.getRotation() == Surface.ROTATION_180) {
- rotation = 180;
- }
-
- CameraInfo cameraInfo = new CameraInfo();
- Camera.getCameraInfo(mCameraId, cameraInfo);
- if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
- mCamera.setDisplayOrientation((cameraInfo.orientation - rotation + 360) % 360);
- } else {
- mCamera.setDisplayOrientation((cameraInfo.orientation + rotation) % 360);
- }
-
- requestLayout();
- mCamera.setParameters(parameters);
- mCamera.startPreview();
- }
-}
\ No newline at end of file
diff --git a/src/org/linphone/ui/Digit.java b/src/org/linphone/ui/Digit.java
index 83e74661a..943ebb70a 100644
--- a/src/org/linphone/ui/Digit.java
+++ b/src/org/linphone/ui/Digit.java
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.ui;
-import org.linphone.DialerActivity;
+import org.linphone.DialerFragment;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.R;
@@ -104,7 +104,7 @@ public class Digit extends Button implements AddressAware {
LinphoneCore lc = LinphoneManager.getLc();
lc.stopDtmf();
mIsDtmfStarted =false;
- if (lc.isIncall() && !DialerActivity.instance().mVisible) {
+ if (lc.isIncall() && !DialerFragment.instance().mVisible) {
lc.sendDtmf(mKeyCode.charAt(0));
}
}
diff --git a/src/org/linphone/ui/EraseButton.java b/src/org/linphone/ui/EraseButton.java
index 289b8fa50..375c797e1 100644
--- a/src/org/linphone/ui/EraseButton.java
+++ b/src/org/linphone/ui/EraseButton.java
@@ -23,9 +23,9 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
-import android.widget.Button;
+import android.widget.ImageView;
-public class EraseButton extends Button implements AddressAware, OnClickListener, OnLongClickListener{
+public class EraseButton extends ImageView implements AddressAware, OnClickListener, OnLongClickListener{
private AddressText address;
diff --git a/src/org/linphone/ui/HangCallButton.java b/src/org/linphone/ui/HangCallButton.java
deleted file mode 100644
index 9194c844d..000000000
--- a/src/org/linphone/ui/HangCallButton.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-HangCallButton.java
-Copyright (C) 2010 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.ui;
-
-import org.linphone.LinphoneManager;
-import org.linphone.core.LinphoneCore;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ImageButton;
-
-public class HangCallButton extends ImageButton implements OnClickListener {
-
- private boolean terminateAllCalls;
- public void setTerminateAllCalls(boolean all) {terminateAllCalls = all;}
-
- private OnClickListener externalClickListener;
- public void setExternalClickListener(OnClickListener e) {externalClickListener = e;}
-
- public HangCallButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- setOnClickListener(this);
- }
-
- public void onClick(View v) {
- LinphoneCore lc = LinphoneManager.getLc();
- if (terminateAllCalls) {
- lc.terminateAllCalls();
- } else {
- lc.terminateCall(lc.getCurrentCall());
- }
-
- if (externalClickListener != null) externalClickListener.onClick(v);
- }
-}
diff --git a/src/org/linphone/ui/IncallTimer.java b/src/org/linphone/ui/IncallTimer.java
deleted file mode 100644
index 34f693be1..000000000
--- a/src/org/linphone/ui/IncallTimer.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-IncallTimer.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.ui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-/**
- * Widget displaying a time
- * @author Guillaume Beraudo
- *
- */
-public class IncallTimer extends TextView {
-
- public IncallTimer(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public IncallTimer(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public IncallTimer(Context context) {
- super(context);
- }
-
-
- @Override
- public void setText(CharSequence text, BufferType type) {
- try {
- int seconds = Integer.parseInt(text.toString());
- super.setText(formatTime(seconds), type);
- } catch (Throwable e) {
- super.setText(text, type);
- }
- }
-
- protected String formatTime(final int seconds) {
- String time = String.format("%02d:%02d",
- (seconds / 60) % 60,
- seconds % 60);
-
- int hours = seconds / 3600;
- if (hours != 0) {
- return hours + ":" + time;
- } else {
- return time;
- }
- }
-
- public void setDuration(int duration) {
- super.setText(formatTime(duration));
- }
-}
diff --git a/src/org/linphone/ui/LinphoneSliders.java b/src/org/linphone/ui/LinphoneSliders.java
new file mode 100644
index 000000000..b890516e0
--- /dev/null
+++ b/src/org/linphone/ui/LinphoneSliders.java
@@ -0,0 +1,140 @@
+package org.linphone.ui;
+
+import org.linphone.R;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.GestureDetector.OnGestureListener;
+import android.view.MotionEvent;
+import android.view.View;
+
+/*
+LinphoneSliders.java
+Copyright (C) 2012 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.
+*/
+
+/**
+ * @author Sylvain Berfini
+ */
+public class LinphoneSliders extends View implements OnGestureListener {
+ private Drawable leftSliderImg, rightSliderImg;
+ private int leftSliderX, rightSliderX;
+ private int slidersHeight, slidersWidth;
+ private GestureDetector mGestures;
+ private LinphoneSliderTriggered mTriggerListener;
+ private boolean slidingLeftHandle, slidingRightHandle;
+ private static final double mCoeff = 0.5;
+
+ public LinphoneSliders(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mGestures = new GestureDetector(getContext(), this);
+ leftSliderImg = getResources().getDrawable(R.drawable.slider_left);
+ rightSliderImg = getResources().getDrawable(R.drawable.slider_right);
+
+ slidersHeight = leftSliderImg.getIntrinsicHeight();
+ slidersWidth = leftSliderImg.getIntrinsicWidth();
+
+ leftSliderX = 0;
+ rightSliderX = 0;
+ slidingLeftHandle = slidingRightHandle = false;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ rightSliderImg.setBounds(getWidth() - slidersWidth - rightSliderX, getHeight() - slidersHeight, getWidth(), getHeight());
+ rightSliderImg.draw(canvas);
+
+ leftSliderImg.setBounds(0, getHeight() - slidersHeight, slidersWidth + leftSliderX, getHeight());
+ leftSliderImg.draw(canvas);
+
+ if (slidingLeftHandle && Math.abs(leftSliderX) >= mCoeff * getWidth()) {
+ mTriggerListener.onLeftHandleTriggered();
+ } else if (slidingRightHandle && rightSliderX >= mCoeff * getWidth()) {
+ mTriggerListener.onRightHandleTriggered();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ leftSliderX = 0;
+ rightSliderX = 0;
+ slidingLeftHandle = slidingRightHandle = false;
+ invalidate();
+ }
+
+ return mGestures.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onDown(MotionEvent e) {
+ return true;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+ float velocityY) {
+ return false;
+ }
+
+ @Override
+ public void onLongPress(MotionEvent e) {
+
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
+ float distanceY) {
+ if (e1.getY() < getHeight() - slidersHeight) {
+ return false;
+ }
+
+ if (e1.getX() < getWidth() / 2) {
+ leftSliderX -= distanceX;
+ slidingLeftHandle = true;
+ } else {
+ rightSliderX += distanceX;
+ slidingRightHandle = true;
+ }
+ invalidate();
+
+ return true;
+ }
+
+ @Override
+ public void onShowPress(MotionEvent e) {
+
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ return false;
+ }
+
+ public void setOnTriggerListener(LinphoneSliderTriggered listener) {
+ mTriggerListener = listener;
+ }
+
+ public interface LinphoneSliderTriggered {
+ public void onLeftHandleTriggered();
+ public void onRightHandleTriggered();
+ }
+}
+
diff --git a/src/org/linphone/ui/LockableSlidingDrawer.java b/src/org/linphone/ui/LockableSlidingDrawer.java
deleted file mode 100644
index 07460fc99..000000000
--- a/src/org/linphone/ui/LockableSlidingDrawer.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.linphone.ui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.SlidingDrawer;
-
-public class LockableSlidingDrawer extends SlidingDrawer {
- private boolean locked = false;
-
- public LockableSlidingDrawer(Context context) {
- super(context, null, 0);
- }
-
- public LockableSlidingDrawer(Context context, AttributeSet attrs) {
- super(context, attrs, 0);
- }
-
- public LockableSlidingDrawer(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (this.locked) {
- return false;
- }
-
- return super.onTouchEvent(event);
- }
-
- public void lock() {
- this.locked = true;
- }
-}
\ No newline at end of file
diff --git a/src/org/linphone/ui/MuteMicButton.java b/src/org/linphone/ui/MuteMicButton.java
deleted file mode 100644
index 42c35bdd0..000000000
--- a/src/org/linphone/ui/MuteMicButton.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-SpeakerButton.java
-Copyright (C) 2010 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.ui;
-
-import org.linphone.LinphoneManager;
-import org.linphone.ui.ToggleImageButton.OnCheckedChangeListener;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-/**
- * @author Guillaume Beraudo
- *
- */
-public class MuteMicButton extends ToggleImageButton implements OnCheckedChangeListener {
-
- public MuteMicButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- setOnCheckedChangeListener(this);
- }
-
-
- public boolean isMicMuted() {
- return isChecked();
- }
-
- public void setMicMuted(boolean state) {
- if (state != isChecked())
- setChecked(state);
- }
-
-
- public void onCheckedChanged(ToggleImageButton button, boolean checked) {
- LinphoneManager.getLc().muteMic(checked);
- }
-}
diff --git a/src/org/linphone/ui/SlidingTab.java b/src/org/linphone/ui/SlidingTab.java
deleted file mode 100644
index c58670e39..000000000
--- a/src/org/linphone/ui/SlidingTab.java
+++ /dev/null
@@ -1,844 +0,0 @@
-/*
- * Derived from Android "SlidingTab" source.
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.linphone.ui;
-
-
-import org.linphone.R;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Vibrator;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.TranslateAnimation;
-import android.view.animation.Animation.AnimationListener;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.ImageView.ScaleType;
-
-/**
- * A special widget containing two Sliders and a threshold for each. Moving either slider beyond
- * the threshold will cause the registered OnTriggerListener.onTrigger() to be called with
- * whichHandle being {@link OnTriggerListener#LEFT_HANDLE} or {@link OnTriggerListener#RIGHT_HANDLE}
- * Equivalently, selecting a tab will result in a call to
- * {@link OnTriggerListener#onGrabbedStateChange(View, int)} with one of these two states. Releasing
- * the tab will result in whichHandle being {@link OnTriggerListener#NO_HANDLE}.
- *
- */
-public class SlidingTab extends ViewGroup {
- private static final String LOG_TAG = "SlidingTab";
- private static final int HORIZONTAL = 0; // as defined in attrs.xml
- private static final int VERTICAL = 1;
-
- // TODO: Make these configurable
- private static final float THRESHOLD = 2.0f / 3.0f;
- private static final long VIBRATE_SHORT = 30;
- private static final long VIBRATE_LONG = 40;
- private static final int TRACKING_MARGIN = 50;
- private static final int ANIM_DURATION = 250; // Time for most animations (in ms)
- private static final int ANIM_TARGET_TIME = 500; // Time to show targets (in ms)
- private boolean mHoldLeftOnTransition = false;
- private boolean mHoldRightOnTransition = false;
-
- private OnTriggerListener mOnTriggerListener;
- private int mGrabbedState = OnTriggerListener.NO_HANDLE;
- private boolean mTriggered = false;
- private Vibrator mVibrator;
-
- /**
- * Either {@link #HORIZONTAL} or {@link #VERTICAL}.
- */
- private int mOrientation;
-
- private Slider mLeftSlider;
- private Slider mRightSlider;
- private Slider mCurrentSlider;
- private boolean mTracking;
- private float mThreshold;
- private Slider mOtherSlider;
- private boolean mAnimating;
- private Rect mTmpRect;
-
- /**
- * Listener used to reset the view when the current animation completes.
- */
- private final AnimationListener mAnimationDoneListener = new AnimationListener() {
- public void onAnimationStart(Animation animation) {
-
- }
-
- public void onAnimationRepeat(Animation animation) {
-
- }
-
- public void onAnimationEnd(Animation animation) {
- onAnimationDone();
- }
- };
-
- /**
- * Interface definition for a callback to be invoked when a tab is triggered
- * by moving it beyond a threshold.
- */
- public interface OnTriggerListener {
- /**
- * The interface was triggered because the user let go of the handle without reaching the
- * threshold.
- */
- public static final int NO_HANDLE = 0;
-
- /**
- * The interface was triggered because the user grabbed the left handle and moved it past
- * the threshold.
- */
- public static final int LEFT_HANDLE = 1;
-
- /**
- * The interface was triggered because the user grabbed the right handle and moved it past
- * the threshold.
- */
- public static final int RIGHT_HANDLE = 2;
-
- /**
- * Called when the user moves a handle beyond the threshold.
- *
- * @param v The view that was triggered.
- * @param whichHandle Which "dial handle" the user grabbed,
- * either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}.
- */
- void onTrigger(View v, int whichHandle);
-
- /**
- * Called when the "grabbed state" changes (i.e. when the user either grabs or releases
- * one of the handles.)
- *
- * @param v the view that was triggered
- * @param grabbedState the new state: {@link #NO_HANDLE}, {@link #LEFT_HANDLE},
- * or {@link #RIGHT_HANDLE}.
- */
- void onGrabbedStateChange(View v, int grabbedState);
- }
-
- /**
- * Simple container class for all things pertinent to a slider.
- * A slider consists of 3 Views:
- *
- * {@link #tab} is the tab shown on the screen in the default state.
- * {@link #text} is the view revealed as the user slides the tab out.
- * {@link #target} is the target the user must drag the slider past to trigger the slider.
- *
- */
- private static class Slider {
- /**
- * Tab alignment - determines which side the tab should be drawn on
- */
- public static final int ALIGN_LEFT = 0;
- public static final int ALIGN_RIGHT = 1;
- public static final int ALIGN_TOP = 2;
- public static final int ALIGN_BOTTOM = 3;
- public static final int ALIGN_UNKNOWN = 4;
-
- /**
- * States for the view.
- */
- private static final int STATE_NORMAL = 0;
- private static final int STATE_PRESSED = 1;
- private static final int STATE_ACTIVE = 2;
-
- private final ImageView tab;
- private final TextView text;
- private final ImageView target;
- private int currentState = STATE_NORMAL;
- private int alignment = ALIGN_UNKNOWN;
- private int alignment_value;
-
- /**
- * Constructor
- *
- * @param parent the container view of this one
- * @param tabId drawable for the tab
- * @param barId drawable for the bar
- * @param targetId drawable for the target
- */
- Slider(ViewGroup parent, int iconId, int tabId, int barId, int targetId) {
- // Create tab
- tab = new ImageView(parent.getContext());
- tab.setImageResource(iconId);
- tab.setBackgroundResource(tabId);
- tab.setScaleType(ScaleType.CENTER);
- tab.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT));
-
- // Create hint TextView
- text = new TextView(parent.getContext());
- text.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.FILL_PARENT));
- text.setBackgroundResource(barId);
- text.setTextAppearance(parent.getContext(), R.style.TextAppearance_SlidingTabNormal);
- // hint.setSingleLine(); // Hmm.. this causes the text to disappear off-screen
-
- // Create target
- target = new ImageView(parent.getContext());
- target.setImageResource(targetId);
- target.setScaleType(ScaleType.CENTER);
- target.setLayoutParams(
- new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- target.setVisibility(View.INVISIBLE);
-
- parent.addView(target); // this needs to be first - relies on painter's algorithm
- parent.addView(tab);
- parent.addView(text);
- }
-
- void setIcon(int iconId) {
- tab.setImageResource(iconId);
- }
-
- void setTabBackgroundResource(int tabId) {
- tab.setBackgroundResource(tabId);
- }
-
- void setBarBackgroundResource(int barId) {
- text.setBackgroundResource(barId);
- }
-
- void setHintText(int resId) {
- text.setText(resId);
- }
-
- void hide() {
- boolean horiz = alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT;
- int dx = horiz ? (alignment == ALIGN_LEFT ? alignment_value - tab.getRight()
- : alignment_value - tab.getLeft()) : 0;
- int dy = horiz ? 0 : (alignment == ALIGN_TOP ? alignment_value - tab.getBottom()
- : alignment_value - tab.getTop());
-
- Animation trans = new TranslateAnimation(0, dx, 0, dy);
- trans.setDuration(ANIM_DURATION);
- trans.setFillAfter(true);
- tab.startAnimation(trans);
- text.startAnimation(trans);
- target.setVisibility(View.INVISIBLE);
- }
-
- void show(boolean animate) {
- text.setVisibility(View.VISIBLE);
- tab.setVisibility(View.VISIBLE);
- //target.setVisibility(View.INVISIBLE);
- if (animate) {
- boolean horiz = alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT;
- int dx = horiz ? (alignment == ALIGN_LEFT ? tab.getWidth() : -tab.getWidth()) : 0;
- int dy = horiz ? 0: (alignment == ALIGN_TOP ? tab.getHeight() : -tab.getHeight());
-
- Animation trans = new TranslateAnimation(-dx, 0, -dy, 0);
- trans.setDuration(ANIM_DURATION);
- tab.startAnimation(trans);
- text.startAnimation(trans);
- }
- }
-
- void setState(int state) {
- text.setPressed(state == STATE_PRESSED);
- tab.setPressed(state == STATE_PRESSED);
- if (state == STATE_ACTIVE) {
- final int[] activeState = new int[] {android.R.attr.state_active};
- if (text.getBackground().isStateful()) {
- text.getBackground().setState(activeState);
- }
- if (tab.getBackground().isStateful()) {
- tab.getBackground().setState(activeState);
- }
- text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabActive);
- } else {
- text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
- }
- currentState = state;
- }
-
- void showTarget() {
- AlphaAnimation alphaAnim = new AlphaAnimation(0.0f, 1.0f);
- alphaAnim.setDuration(ANIM_TARGET_TIME);
- target.startAnimation(alphaAnim);
- target.setVisibility(View.VISIBLE);
- }
-
- void reset(boolean animate) {
- setState(STATE_NORMAL);
- text.setVisibility(View.VISIBLE);
- text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
- tab.setVisibility(View.VISIBLE);
- target.setVisibility(View.INVISIBLE);
- final boolean horiz = alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT;
- int dx = horiz ? (alignment == ALIGN_LEFT ? alignment_value - tab.getLeft()
- : alignment_value - tab.getRight()) : 0;
- int dy = horiz ? 0 : (alignment == ALIGN_TOP ? alignment_value - tab.getTop()
- : alignment_value - tab.getBottom());
- if (animate) {
- TranslateAnimation trans = new TranslateAnimation(0, dx, 0, dy);
- trans.setDuration(ANIM_DURATION);
- trans.setFillAfter(false);
- text.startAnimation(trans);
- tab.startAnimation(trans);
- } else {
- if (horiz) {
- text.offsetLeftAndRight(dx);
- tab.offsetLeftAndRight(dx);
- } else {
- text.offsetTopAndBottom(dy);
- tab.offsetTopAndBottom(dy);
- }
- text.clearAnimation();
- tab.clearAnimation();
- target.clearAnimation();
- }
- }
-
- void setTarget(int targetId) {
- target.setImageResource(targetId);
- }
-
- /**
- * Layout the given widgets within the parent.
- *
- * @param l the parent's left border
- * @param t the parent's top border
- * @param r the parent's right border
- * @param b the parent's bottom border
- * @param alignment which side to align the widget to
- */
- void layout(int l, int t, int r, int b, int alignment) {
- this.alignment = alignment;
- final Drawable tabBackground = tab.getBackground();
- final int handleWidth = tabBackground.getIntrinsicWidth();
- final int handleHeight = tabBackground.getIntrinsicHeight();
- final Drawable targetDrawable = target.getDrawable();
- final int targetWidth = targetDrawable.getIntrinsicWidth();
- final int targetHeight = targetDrawable.getIntrinsicHeight();
- final int parentWidth = r - l;
- final int parentHeight = b - t;
-
- final int leftTarget = (int) (THRESHOLD * parentWidth) - targetWidth + handleWidth / 2;
- final int rightTarget = (int) ((1.0f - THRESHOLD) * parentWidth) - handleWidth / 2;
- final int left = (parentWidth - handleWidth) / 2;
- final int right = left + handleWidth;
-
- if (alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT) {
- // horizontal
- final int targetTop = (parentHeight - targetHeight) / 2;
- final int targetBottom = targetTop + targetHeight;
- final int top = (parentHeight - handleHeight) / 2;
- final int bottom = (parentHeight + handleHeight) / 2;
- if (alignment == ALIGN_LEFT) {
- tab.layout(0, top, handleWidth, bottom);
- text.layout(0 - parentWidth, top, 0, bottom);
- text.setGravity(Gravity.RIGHT);
- target.layout(leftTarget, targetTop, leftTarget + targetWidth, targetBottom);
- alignment_value = l;
- } else {
- tab.layout(parentWidth - handleWidth, top, parentWidth, bottom);
- text.layout(parentWidth, top, parentWidth + parentWidth, bottom);
- target.layout(rightTarget, targetTop, rightTarget + targetWidth, targetBottom);
- text.setGravity(Gravity.TOP);
- alignment_value = r;
- }
- } else {
- // vertical
- final int targetLeft = (parentWidth - targetWidth) / 2;
- final int targetRight = (parentWidth + targetWidth) / 2;
- final int top = (int) (THRESHOLD * parentHeight) + handleHeight / 2 - targetHeight;
- final int bottom = (int) ((1.0f - THRESHOLD) * parentHeight) - handleHeight / 2;
- if (alignment == ALIGN_TOP) {
- tab.layout(left, 0, right, handleHeight);
- text.layout(left, 0 - parentHeight, right, 0);
- target.layout(targetLeft, top, targetRight, top + targetHeight);
- alignment_value = t;
- } else {
- tab.layout(left, parentHeight - handleHeight, right, parentHeight);
- text.layout(left, parentHeight, right, parentHeight + parentHeight);
- target.layout(targetLeft, bottom, targetRight, bottom + targetHeight);
- alignment_value = b;
- }
- }
- }
-
- public void updateDrawableStates() {
- setState(currentState);
- }
-
- /**
- * Ensure all the dependent widgets are measured.
- */
- public void measure() {
- tab.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
- text.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
- }
-
- /**
- * Get the measured tab width. Must be called after {@link Slider#measure()}.
- * @return
- */
- public int getTabWidth() {
- return tab.getMeasuredWidth();
- }
-
- /**
- * Get the measured tab width. Must be called after {@link Slider#measure()}.
- * @return
- */
- public int getTabHeight() {
- return tab.getMeasuredHeight();
- }
-
- /**
- * Start animating the slider. Note we need two animations since an Animator
- * keeps internal state of the invalidation region which is just the view being animated.
- *
- * @param anim1
- * @param anim2
- */
- public void startAnimation(Animation anim1, Animation anim2) {
- tab.startAnimation(anim1);
- text.startAnimation(anim2);
- }
-
- public void hideTarget() {
- target.clearAnimation();
- target.setVisibility(View.INVISIBLE);
- }
- }
-
- public SlidingTab(Context context) {
- this(context, null);
- }
-
- /**
- * Constructor used when this widget is created from a layout file.
- */
- public SlidingTab(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- // Allocate a temporary once that can be used everywhere.
- mTmpRect = new Rect();
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingTab);
- mOrientation = a.getInt(org.linphone.R.styleable.SlidingTab_orientation, HORIZONTAL);
- a.recycle();
- mLeftSlider = new Slider(this,
- R.drawable.startcall_green,
- R.drawable.jog_tab_left_answer,
- R.drawable.jog_tab_bar_left_answer,
- R.drawable.jog_tab_target_green
- );
- mRightSlider = new Slider(this,
- R.drawable.stopcall_red,
- R.drawable.jog_tab_right_decline,
- R.drawable.jog_tab_bar_right_decline,
- R.drawable.jog_tab_target_red
- );
-
- // setBackgroundColor(0x80808080);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
- int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
- Log.e("SlidingTab", "SlidingTab cannot have UNSPECIFIED MeasureSpec"
- +"(wspec=" + widthSpecMode + ", hspec=" + heightSpecMode + ")",
- new RuntimeException(LOG_TAG + "stack:"));
- }
-
- mLeftSlider.measure();
- mRightSlider.measure();
- final int leftTabWidth = mLeftSlider.getTabWidth();
- final int rightTabWidth = mRightSlider.getTabWidth();
- final int leftTabHeight = mLeftSlider.getTabHeight();
- final int rightTabHeight = mRightSlider.getTabHeight();
- final int width;
- final int height;
- if (isHorizontal()) {
- width = Math.max(widthSpecSize, leftTabWidth + rightTabWidth);
- height = Math.max(leftTabHeight, rightTabHeight);
- } else {
- width = Math.max(leftTabWidth, rightTabHeight);
- height = Math.max(heightSpecSize, leftTabHeight + rightTabHeight);
- }
- setMeasuredDimension(width, height);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- final int action = event.getAction();
- final float x = event.getX();
- final float y = event.getY();
-
- if (mAnimating) {
- return false;
- }
-
- View leftHandle = mLeftSlider.tab;
- leftHandle.getHitRect(mTmpRect);
- boolean leftHit = mTmpRect.contains((int) x, (int) y);
-
- View rightHandle = mRightSlider.tab;
- rightHandle.getHitRect(mTmpRect);
- boolean rightHit = mTmpRect.contains((int)x, (int) y);
-
- if (!mTracking && !(leftHit || rightHit)) {
- return false;
- }
-
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- mTracking = true;
- mTriggered = false;
- vibrate(VIBRATE_SHORT);
- if (leftHit) {
- mCurrentSlider = mLeftSlider;
- mOtherSlider = mRightSlider;
- mThreshold = isHorizontal() ? THRESHOLD : 1.0f - THRESHOLD;
- setGrabbedState(OnTriggerListener.LEFT_HANDLE);
- } else {
- mCurrentSlider = mRightSlider;
- mOtherSlider = mLeftSlider;
- mThreshold = isHorizontal() ? 1.0f - THRESHOLD : THRESHOLD;
- setGrabbedState(OnTriggerListener.RIGHT_HANDLE);
- }
- mCurrentSlider.setState(Slider.STATE_PRESSED);
- mCurrentSlider.showTarget();
- mOtherSlider.hide();
- break;
- }
- }
-
- return true;
- }
-
- /**
- * Reset the tabs to their original state and stop any existing animation.
- * Animate them back into place if animate is true.
- *
- * @param animate
- */
- public void reset(boolean animate) {
- mLeftSlider.reset(animate);
- mRightSlider.reset(animate);
- if (!animate) {
- mAnimating = false;
- }
- }
-
- @Override
- public void setVisibility(int visibility) {
- // Clear animations so sliders don't continue to animate when we show the widget again.
- if (visibility != getVisibility() && visibility == View.INVISIBLE) {
- reset(false);
- }
- super.setVisibility(visibility);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mTracking) {
- final int action = event.getAction();
- final float x = event.getX();
- final float y = event.getY();
-
- switch (action) {
- case MotionEvent.ACTION_MOVE:
- if (withinView(x, y, this) ) {
- moveHandle(x, y);
- float position = isHorizontal() ? x : y;
- float target = mThreshold * (isHorizontal() ? getWidth() : getHeight());
- boolean thresholdReached;
- if (isHorizontal()) {
- thresholdReached = mCurrentSlider == mLeftSlider ?
- position > target : position < target;
- } else {
- thresholdReached = mCurrentSlider == mLeftSlider ?
- position < target : position > target;
- }
- if (!mTriggered && thresholdReached) {
- mTriggered = true;
- mTracking = false;
- mCurrentSlider.setState(Slider.STATE_ACTIVE);
- boolean isLeft = mCurrentSlider == mLeftSlider;
- dispatchTriggerEvent(isLeft ?
- OnTriggerListener.LEFT_HANDLE : OnTriggerListener.RIGHT_HANDLE);
-
- startAnimating(isLeft ? mHoldLeftOnTransition : mHoldRightOnTransition);
- setGrabbedState(OnTriggerListener.NO_HANDLE);
- }
- break;
- }
- // Intentionally fall through - we're outside tracking rectangle
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mTracking = false;
- mTriggered = false;
- mOtherSlider.show(true);
- mCurrentSlider.reset(false);
- mCurrentSlider.hideTarget();
- mCurrentSlider = null;
- mOtherSlider = null;
- setGrabbedState(OnTriggerListener.NO_HANDLE);
- break;
- }
- }
-
- return mTracking || super.onTouchEvent(event);
- }
-
- void startAnimating(final boolean holdAfter) {
- mAnimating = true;
- final Animation trans1;
- final Animation trans2;
- final Slider slider = mCurrentSlider;
- final int dx;
- final int dy;
- if (isHorizontal()) {
- int right = slider.tab.getRight();
- int width = slider.tab.getWidth();
- int left = slider.tab.getLeft();
- int viewWidth = getWidth();
- int holdOffset = holdAfter ? 0 : width; // how much of tab to show at the end of anim
- dx = slider == mRightSlider ? - (right + viewWidth - holdOffset)
- : (viewWidth - left) + viewWidth - holdOffset;
- dy = 0;
- } else {
- int top = slider.tab.getTop();
- int bottom = slider.tab.getBottom();
- int height = slider.tab.getHeight();
- int viewHeight = getHeight();
- int holdOffset = holdAfter ? 0 : height; // how much of tab to show at end of anim
- dx = 0;
- dy = slider == mRightSlider ? (top + viewHeight - holdOffset)
- : - ((viewHeight - bottom) + viewHeight - holdOffset);
- }
- trans1 = new TranslateAnimation(0, dx, 0, dy);
- trans1.setDuration(ANIM_DURATION);
- trans1.setInterpolator(new LinearInterpolator());
- trans1.setFillAfter(true);
- trans2 = new TranslateAnimation(0, dx, 0, dy);
- trans2.setDuration(ANIM_DURATION);
- trans2.setInterpolator(new LinearInterpolator());
- trans2.setFillAfter(true);
-
- trans1.setAnimationListener(new AnimationListener() {
- public void onAnimationEnd(Animation animation) {
- Animation anim;
- if (holdAfter) {
- anim = new TranslateAnimation(dx, dx, dy, dy);
- anim.setDuration(1000); // plenty of time for transitions
- mAnimating = false;
- } else {
- anim = new AlphaAnimation(0.5f, 1.0f);
- anim.setDuration(ANIM_DURATION);
- resetView();
- }
- anim.setAnimationListener(mAnimationDoneListener);
-
- /* Animation can be the same for these since the animation just holds */
- mLeftSlider.startAnimation(anim, anim);
- mRightSlider.startAnimation(anim, anim);
- }
-
- public void onAnimationRepeat(Animation animation) {
-
- }
-
- public void onAnimationStart(Animation animation) {
-
- }
-
- });
-
- slider.hideTarget();
- slider.startAnimation(trans1, trans2);
- }
-
- private void onAnimationDone() {
- resetView();
- mAnimating = false;
- }
-
- private boolean withinView(final float x, final float y, final View view) {
- return isHorizontal() && y > - TRACKING_MARGIN && y < TRACKING_MARGIN + view.getHeight()
- || !isHorizontal() && x > -TRACKING_MARGIN && x < TRACKING_MARGIN + view.getWidth();
- }
-
- private boolean isHorizontal() {
- return mOrientation == HORIZONTAL;
- }
-
- private void resetView() {
- mLeftSlider.reset(false);
- mRightSlider.reset(false);
- // onLayout(true, getLeft(), getTop(), getLeft() + getWidth(), getTop() + getHeight());
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- if (!changed) return;
-
- // Center the widgets in the view
- mLeftSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_LEFT : Slider.ALIGN_BOTTOM);
- mRightSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_RIGHT : Slider.ALIGN_TOP);
- }
-
- private void moveHandle(float x, float y) {
- final View handle = mCurrentSlider.tab;
- final View content = mCurrentSlider.text;
- if (isHorizontal()) {
- int deltaX = (int) x - handle.getLeft() - (handle.getWidth() / 2);
- handle.offsetLeftAndRight(deltaX);
- content.offsetLeftAndRight(deltaX);
- } else {
- int deltaY = (int) y - handle.getTop() - (handle.getHeight() / 2);
- handle.offsetTopAndBottom(deltaY);
- content.offsetTopAndBottom(deltaY);
- }
- invalidate(); // TODO: be more conservative about what we're invalidating
- }
-
- /**
- * Sets the left handle icon to a given resource.
- *
- * The resource should refer to a Drawable object, or use 0 to remove
- * the icon.
- *
- * @param iconId the resource ID of the icon drawable
- * @param targetId the resource of the target drawable
- * @param barId the resource of the bar drawable (stateful)
- * @param tabId the resource of the
- */
- public void setLeftTabResources(int iconId, int targetId, int barId, int tabId) {
- mLeftSlider.setIcon(iconId);
- mLeftSlider.setTarget(targetId);
- mLeftSlider.setBarBackgroundResource(barId);
- mLeftSlider.setTabBackgroundResource(tabId);
- mLeftSlider.updateDrawableStates();
- }
-
- /**
- * Sets the left handle hint text to a given resource string.
- *
- * @param resId
- */
- public void setLeftHintText(int resId) {
- if (isHorizontal()) {
- mLeftSlider.setHintText(resId);
- }
- }
-
- /**
- * Sets the right handle icon to a given resource.
- *
- * The resource should refer to a Drawable object, or use 0 to remove
- * the icon.
- *
- * @param iconId the resource ID of the icon drawable
- * @param targetId the resource of the target drawable
- * @param barId the resource of the bar drawable (stateful)
- * @param tabId the resource of the
- */
- public void setRightTabResources(int iconId, int targetId, int barId, int tabId) {
- mRightSlider.setIcon(iconId);
- mRightSlider.setTarget(targetId);
- mRightSlider.setBarBackgroundResource(barId);
- mRightSlider.setTabBackgroundResource(tabId);
- mRightSlider.updateDrawableStates();
- }
-
- /**
- * Sets the left handle hint text to a given resource string.
- *
- * @param resId
- */
- public void setRightHintText(int resId) {
- if (isHorizontal()) {
- mRightSlider.setHintText(resId);
- }
- }
-
- public void setHoldAfterTrigger(boolean holdLeft, boolean holdRight) {
- mHoldLeftOnTransition = holdLeft;
- mHoldRightOnTransition = holdRight;
- }
-
- /**
- * Triggers haptic feedback.
- */
- private synchronized void vibrate(long duration) {
- if (mVibrator == null) {
- mVibrator = (android.os.Vibrator)
- getContext().getSystemService(Context.VIBRATOR_SERVICE);
- }
- mVibrator.vibrate(duration);
- }
-
- /**
- * Registers a callback to be invoked when the user triggers an event.
- *
- * @param listener the OnDialTriggerListener to attach to this view
- */
- public void setOnTriggerListener(OnTriggerListener listener) {
- mOnTriggerListener = listener;
- }
-
- /**
- * Dispatches a trigger event to listener. Ignored if a listener is not set.
- * @param whichHandle the handle that triggered the event.
- */
- private void dispatchTriggerEvent(int whichHandle) {
- vibrate(VIBRATE_LONG);
- if (mOnTriggerListener != null) {
- mOnTriggerListener.onTrigger(this, whichHandle);
- }
- }
-
- /**
- * Sets the current grabbed state, and dispatches a grabbed state change
- * event to our listener.
- */
- private void setGrabbedState(int newState) {
- if (newState != mGrabbedState) {
- mGrabbedState = newState;
- if (mOnTriggerListener != null) {
- mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
- }
- }
- }
-}
diff --git a/src/org/linphone/ui/SpeakerButton.java b/src/org/linphone/ui/SpeakerButton.java
deleted file mode 100644
index 35d2beb1b..000000000
--- a/src/org/linphone/ui/SpeakerButton.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-SpeakerButton.java
-Copyright (C) 2010 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.ui;
-
-import org.linphone.LinphoneManager;
-import org.linphone.ui.ToggleImageButton.OnCheckedChangeListener;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-/**
- * @author Guillaume Beraudo
- *
- */
-public class SpeakerButton extends ToggleImageButton implements OnCheckedChangeListener {
-
- public SpeakerButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- setOnCheckedChangeListener(this);
- }
-
-
- public boolean isSpeakerOn() {
- return isChecked();
- }
-
- public void setSpeakerOn(boolean state) {
- if (state != isChecked())
- setChecked(state);
- }
-
-
- public void onCheckedChanged(ToggleImageButton button, boolean checked) {
- if (checked) {
- LinphoneManager.getInstance().routeAudioToSpeaker();
- } else {
- LinphoneManager.getInstance().routeAudioToReceiver();
- }
- }
-
-
-}
diff --git a/src/org/linphone/ui/ToggleImageButton.java b/src/org/linphone/ui/ToggleImageButton.java
deleted file mode 100644
index 03899abf8..000000000
--- a/src/org/linphone/ui/ToggleImageButton.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
-ToggleImageButton.java
-Copyright (C) 2010 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.ui;
-
-
-import org.linphone.R;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Checkable;
-import android.widget.ImageButton;
-
-/**
- * Image button storing a checked state to display alternating drawables.
- * The "checked" drawable is displayed when button is down / checked.
- * The "unchecked" drawable is displayed when button is up / unchecked.
- *
- * @author Guillaume Beraudo
- *
- */
-public class ToggleImageButton extends ImageButton implements Checkable, OnClickListener {
- private boolean checked;
- private Drawable stateChecked;
- private Drawable stateUnChecked;
- private boolean drawablesForBackground;
- private OnCheckedChangeListener onCheckedChangeListener;
-
- public ToggleImageButton(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ToggleImageButton);
- stateChecked = getResources().getDrawable(array.getResourceId(R.styleable.ToggleImageButton_checked, -1));
- stateUnChecked = getResources().getDrawable(array.getResourceId(R.styleable.ToggleImageButton_unchecked, -1));
- drawablesForBackground = array.getBoolean(R.styleable.ToggleImageButton_bgdrawables, false);
- setBackgroundColor(Color.TRANSPARENT);
-
- setOnClickListener(this);
- handleCheckChanged();
- }
-
-
-
- public void setChecked(boolean checked) {
- this.checked = checked;
- handleCheckChanged();
- }
-
- public boolean isChecked() {
- return checked;
- }
-
-
- private void handleCheckChanged() {
- Drawable d = checked? stateChecked : stateUnChecked;
- if (drawablesForBackground) {
- setBackgroundDrawable(d);
- } else {
- setImageDrawable(d);
- }
- requestLayout();
- invalidate();
- if (onCheckedChangeListener != null) onCheckedChangeListener.onCheckedChanged(this, checked);
- }
-
-
- public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
- onCheckedChangeListener = listener;
- }
-
- public static interface OnCheckedChangeListener {
- void onCheckedChanged(ToggleImageButton button, boolean checked);
- }
-
- public void onClick(View v) {
- toggle();
- }
-
-
- @Override
- public void toggle() {
- setChecked(!isChecked());
- }
-
- @Override
- public boolean performClick() {
- toggle();
- return super.performClick();
- }
-}
diff --git a/src/org/mediastreamer2/test/Ring.java b/src/org/mediastreamer2/test/Ring.java
deleted file mode 100644
index 361534049..000000000
--- a/src/org/mediastreamer2/test/Ring.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-Ring.java
-Copyright (C) 2010 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.mediastreamer2.test;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-
-import org.linphone.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-
-public class Ring extends Activity {
- Thread mWorkerThread = new Thread("Worker Thread");
- /** Called when the activity is first created. */
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ring);
- try {
- try {
- System.loadLibrary("ring");
- } catch (UnsatisfiedLinkError e) {
- Log.e("mediastreamer2", "cannot load libring.so, did you compile SDK with ndk-build RING=yes ", e);
- }
- final File lFileToPlay = getFileStreamPath("oldphone_mono.wav");
- if (!lFileToPlay.exists()) {
- FileOutputStream lOutputStream = openFileOutput ("oldphone_mono.wav", 0);
- InputStream lInputStream = getResources().openRawResource(R.raw.oldphone_mono);
- int readByte;
- while (( readByte = lInputStream.read())!=-1) {
- lOutputStream.write(readByte);
- }
- lOutputStream.flush();
- lOutputStream.close();
- lInputStream.close();
- }
- init();
- mWorkerThread = new Thread(new Runnable() {
- public void run() {
- play(lFileToPlay.getAbsolutePath());
- echo(44100);
- }
-
- },"Worker Thread");
- mWorkerThread.start();
- } catch (Exception e) {
- Log.e("ring","error",e);
- }
- }
- native void play(String file);
- native void echo(int freq);
- native void init();
-}
-
\ No newline at end of file
diff --git a/submodules/linphone b/submodules/linphone
index 9496394c8..57d9f33e2 160000
--- a/submodules/linphone
+++ b/submodules/linphone
@@ -1 +1 @@
-Subproject commit 9496394c88dbdf6e6dd120b5657a2846b603d612
+Subproject commit 57d9f33e253493cdd1b58dcb0c825181bd23f42b