diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 1cb69dd39..1afc59765 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -101,6 +101,14 @@ + + + + + + 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_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/add_call.xml b/res/drawable/add_call.xml new file mode 100644 index 000000000..e959e24fd --- /dev/null +++ b/res/drawable/add_call.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/res/drawable/add_call_actif.png b/res/drawable/add_call_actif.png new file mode 100644 index 000000000..8dbce108c Binary files /dev/null and b/res/drawable/add_call_actif.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_call_page_contact.png b/res/drawable/add_call_page_contact.png new file mode 100644 index 000000000..f91eeffb6 Binary files /dev/null and b/res/drawable/add_call_page_contact.png differ diff --git a/res/drawable/add_contact.xml b/res/drawable/add_contact.xml new file mode 100644 index 000000000..10690779a --- /dev/null +++ b/res/drawable/add_contact.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/res/drawable/add_contact_actif.png b/res/drawable/add_contact_actif.png new file mode 100644 index 000000000..5da115460 Binary files /dev/null and b/res/drawable/add_contact_actif.png differ diff --git a/res/drawable/add_contact_inactif.png b/res/drawable/add_contact_inactif.png new file mode 100644 index 000000000..337a99e51 Binary files /dev/null and b/res/drawable/add_contact_inactif.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_actif.png b/res/drawable/all_actif.png new file mode 100644 index 000000000..18e7eebd4 Binary files /dev/null and b/res/drawable/all_actif.png differ diff --git a/res/drawable/all_call.xml b/res/drawable/all_call.xml new file mode 100644 index 000000000..82e90c292 --- /dev/null +++ b/res/drawable/all_call.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/all_call_actif.png b/res/drawable/all_call_actif.png new file mode 100644 index 000000000..fe9f61f2f Binary files /dev/null and b/res/drawable/all_call_actif.png differ diff --git a/res/drawable/all_call_selectionne.png b/res/drawable/all_call_selectionne.png new file mode 100644 index 000000000..9790cc945 Binary files /dev/null and b/res/drawable/all_call_selectionne.png differ diff --git a/res/drawable/all_contacts.xml b/res/drawable/all_contacts.xml new file mode 100644 index 000000000..df9f5d634 --- /dev/null +++ b/res/drawable/all_contacts.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/all_selectionne.png b/res/drawable/all_selectionne.png new file mode 100644 index 000000000..d062ce11c Binary files /dev/null and b/res/drawable/all_selectionne.png differ diff --git a/res/drawable/appeler.xml b/res/drawable/appeler.xml new file mode 100644 index 000000000..da780bf0d --- /dev/null +++ b/res/drawable/appeler.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/appeler_actif.png b/res/drawable/appeler_actif.png new file mode 100644 index 000000000..fc2792247 Binary files /dev/null and b/res/drawable/appeler_actif.png differ diff --git a/res/drawable/appeler_over.png b/res/drawable/appeler_over.png new file mode 100644 index 000000000..9cbf18c60 Binary files /dev/null and b/res/drawable/appeler_over.png differ diff --git a/res/drawable/backspace.xml b/res/drawable/backspace.xml new file mode 100644 index 000000000..654c9a576 --- /dev/null +++ b/res/drawable/backspace.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/backspace_actif.png b/res/drawable/backspace_actif.png new file mode 100644 index 000000000..b19ba4fa1 Binary files /dev/null and b/res/drawable/backspace_actif.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/barre_noire_top.png b/res/drawable/barre_noire_top.png new file mode 100644 index 000000000..001991fb0 Binary files /dev/null and b/res/drawable/barre_noire_top.png differ diff --git a/res/drawable/button.xml b/res/drawable/button.xml new file mode 100644 index 000000000..53dd273e4 --- /dev/null +++ b/res/drawable/button.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/button_background_actif.png b/res/drawable/button_background_actif.png new file mode 100644 index 000000000..31efad8aa Binary files /dev/null and b/res/drawable/button_background_actif.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..a81d47745 --- /dev/null +++ b/res/drawable/call.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_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/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..b68fb8744 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..f07f35e2d 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..7b045d222 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/champ_saisie_numero.png b/res/drawable/champ_saisie_numero.png new file mode 100644 index 000000000..0751263e1 Binary files /dev/null and b/res/drawable/champ_saisie_numero.png differ diff --git a/res/drawable/chat.xml b/res/drawable/chat.xml new file mode 100644 index 000000000..e3c283277 --- /dev/null +++ b/res/drawable/chat.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/drawable/chat_actif.png b/res/drawable/chat_actif.png new file mode 100644 index 000000000..5e9716cc8 Binary files /dev/null and b/res/drawable/chat_actif.png differ diff --git a/res/drawable/chat_bubble_incoming.9.png b/res/drawable/chat_bubble_incoming.9.png new file mode 100644 index 000000000..6fcc66336 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..363e398b7 Binary files /dev/null and b/res/drawable/chat_bubble_outgoing.9.png differ diff --git a/res/drawable/chat_edit.xml b/res/drawable/chat_edit.xml new file mode 100644 index 000000000..025218616 --- /dev/null +++ b/res/drawable/chat_edit.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/chat_edit_actif.png b/res/drawable/chat_edit_actif.png new file mode 100644 index 000000000..428ce5df8 Binary files /dev/null and b/res/drawable/chat_edit_actif.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..fc097d0c7 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..c84b2d2b8 --- /dev/null +++ b/res/drawable/chat_new.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/chat_new_actif.png b/res/drawable/chat_new_actif.png new file mode 100644 index 000000000..053723d22 Binary files /dev/null and b/res/drawable/chat_new_actif.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..b9c4c463d --- /dev/null +++ b/res/drawable/chat_ok.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/chat_ok_actif.png b/res/drawable/chat_ok_actif.png new file mode 100644 index 000000000..0c49ac3d5 Binary files /dev/null and b/res/drawable/chat_ok_actif.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_selectionne.png b/res/drawable/chat_selectionne.png new file mode 100644 index 000000000..2638c0c10 Binary files /dev/null and b/res/drawable/chat_selectionne.png differ diff --git a/res/drawable/chat_send_message.xml b/res/drawable/chat_send_message.xml new file mode 100644 index 000000000..b77253813 --- /dev/null +++ b/res/drawable/chat_send_message.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/chat_send_message_actif.png b/res/drawable/chat_send_message_actif.png new file mode 100644 index 000000000..1bee48a2f Binary files /dev/null and b/res/drawable/chat_send_message_actif.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/connected_led.png b/res/drawable/connected_led.png new file mode 100644 index 000000000..e788e2b07 Binary files /dev/null and b/res/drawable/connected_led.png differ diff --git a/res/drawable/contacts.xml b/res/drawable/contacts.xml new file mode 100644 index 000000000..93fb4586f --- /dev/null +++ b/res/drawable/contacts.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/drawable/contacts_actif.png b/res/drawable/contacts_actif.png new file mode 100644 index 000000000..88039d6c5 Binary files /dev/null and b/res/drawable/contacts_actif.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_selectionne.png b/res/drawable/contacts_selectionne.png new file mode 100644 index 000000000..baf14ed3e Binary files /dev/null and b/res/drawable/contacts_selectionne.png differ diff --git a/res/drawable/delete.xml b/res/drawable/delete.xml new file mode 100644 index 000000000..68faa1b6c --- /dev/null +++ b/res/drawable/delete.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/delete_actif.png b/res/drawable/delete_actif.png new file mode 100644 index 000000000..ef1ae410e Binary files /dev/null and b/res/drawable/delete_actif.png differ diff --git a/res/drawable/delete_over.png b/res/drawable/delete_over.png new file mode 100644 index 000000000..ec9522b3b Binary files /dev/null and b/res/drawable/delete_over.png differ diff --git a/res/drawable/detail.xml b/res/drawable/detail.xml new file mode 100644 index 000000000..2596026aa --- /dev/null +++ b/res/drawable/detail.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/detail_actif.png b/res/drawable/detail_actif.png new file mode 100644 index 000000000..a4856294d Binary files /dev/null and b/res/drawable/detail_actif.png differ diff --git a/res/drawable/detail_over.png b/res/drawable/detail_over.png new file mode 100644 index 000000000..9cecd5e59 Binary files /dev/null and b/res/drawable/detail_over.png differ diff --git a/res/drawable/dialer.xml b/res/drawable/dialer.xml new file mode 100644 index 000000000..bc1087551 --- /dev/null +++ b/res/drawable/dialer.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/drawable/dialer_actif.png b/res/drawable/dialer_actif.png new file mode 100644 index 000000000..b23fcbb41 Binary files /dev/null and b/res/drawable/dialer_actif.png differ diff --git a/res/drawable/dialer_alt.xml b/res/drawable/dialer_alt.xml new file mode 100644 index 000000000..a4bacb6a8 --- /dev/null +++ b/res/drawable/dialer_alt.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/dialer_alt_actif.png b/res/drawable/dialer_alt_actif.png new file mode 100644 index 000000000..43d512c04 Binary files /dev/null and b/res/drawable/dialer_alt_actif.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_over.png b/res/drawable/dialer_over.png new file mode 100644 index 000000000..2edc47aa3 Binary files /dev/null and b/res/drawable/dialer_over.png differ diff --git a/res/drawable/dialer_selectionne.png b/res/drawable/dialer_selectionne.png new file mode 100644 index 000000000..5883398d2 Binary files /dev/null and b/res/drawable/dialer_selectionne.png differ diff --git a/res/drawable/edit.xml b/res/drawable/edit.xml new file mode 100644 index 000000000..328a21987 --- /dev/null +++ b/res/drawable/edit.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/edit_actif.png b/res/drawable/edit_actif.png new file mode 100644 index 000000000..bfb27dedc Binary files /dev/null and b/res/drawable/edit_actif.png differ diff --git a/res/drawable/edit_over.png b/res/drawable/edit_over.png new file mode 100644 index 000000000..679ae9f8b Binary files /dev/null and b/res/drawable/edit_over.png differ diff --git a/res/drawable/history.xml b/res/drawable/history.xml new file mode 100644 index 000000000..ee5ee1d28 --- /dev/null +++ b/res/drawable/history.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/drawable/history_actif.png b/res/drawable/history_actif.png new file mode 100644 index 000000000..866a25a77 Binary files /dev/null and b/res/drawable/history_actif.png 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_selectionne.png b/res/drawable/history_selectionne.png new file mode 100644 index 000000000..b672b21f3 Binary files /dev/null and b/res/drawable/history_selectionne.png differ diff --git a/res/drawable/incall_contact_actif.png b/res/drawable/incall_contact_actif.png new file mode 100644 index 000000000..d2dbc4ca9 Binary files /dev/null and b/res/drawable/incall_contact_actif.png differ diff --git a/res/drawable/incall_contact_over.png b/res/drawable/incall_contact_over.png new file mode 100644 index 000000000..5a904ef36 Binary files /dev/null and b/res/drawable/incall_contact_over.png differ diff --git a/res/drawable/incall_contacts.xml b/res/drawable/incall_contacts.xml new file mode 100644 index 000000000..72d41e948 --- /dev/null +++ b/res/drawable/incall_contacts.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/drawable/incoming_call.png b/res/drawable/incoming_call.png new file mode 100644 index 000000000..2ce5c676e Binary files /dev/null and b/res/drawable/incoming_call.png differ diff --git a/res/drawable/linphone_actif.png b/res/drawable/linphone_actif.png new file mode 100644 index 000000000..9d240afeb Binary files /dev/null and b/res/drawable/linphone_actif.png differ diff --git a/res/drawable/linphone_contacts.xml b/res/drawable/linphone_contacts.xml new file mode 100644 index 000000000..fc734e9c2 --- /dev/null +++ b/res/drawable/linphone_contacts.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/linphone_selectionne.png b/res/drawable/linphone_selectionne.png new file mode 100644 index 000000000..0a75d15f0 Binary files /dev/null and b/res/drawable/linphone_selectionne.png differ diff --git a/res/drawable/maybe_secure.png b/res/drawable/maybe_secure.png new file mode 100644 index 000000000..1f68accf2 Binary files /dev/null and b/res/drawable/maybe_secure.png differ diff --git a/res/drawable/micro_off.xml b/res/drawable/micro_off.xml new file mode 100644 index 000000000..adc966307 --- /dev/null +++ b/res/drawable/micro_off.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/res/drawable/micro_off_actif.png b/res/drawable/micro_off_actif.png new file mode 100644 index 000000000..2ec3be550 Binary files /dev/null and b/res/drawable/micro_off_actif.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..5b6910e79 --- /dev/null +++ b/res/drawable/micro_on.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/res/drawable/micro_on_actif.png b/res/drawable/micro_on_actif.png new file mode 100644 index 000000000..ca63b44ff Binary files /dev/null and b/res/drawable/micro_on_actif.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/missed.xml b/res/drawable/missed.xml new file mode 100644 index 000000000..4fd87213d --- /dev/null +++ b/res/drawable/missed.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/missed_actif.png b/res/drawable/missed_actif.png new file mode 100644 index 000000000..0f2f99b4e Binary files /dev/null and b/res/drawable/missed_actif.png differ diff --git a/res/drawable/missed_call.png b/res/drawable/missed_call.png new file mode 100644 index 000000000..426dee899 Binary files /dev/null and b/res/drawable/missed_call.png 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/missed_selectionne.png b/res/drawable/missed_selectionne.png new file mode 100644 index 000000000..cb413d997 Binary files /dev/null and b/res/drawable/missed_selectionne.png differ diff --git a/res/drawable/new_contact.xml b/res/drawable/new_contact.xml new file mode 100644 index 000000000..84d70406c --- /dev/null +++ b/res/drawable/new_contact.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/drawable/new_contact_actif.png b/res/drawable/new_contact_actif.png new file mode 100644 index 000000000..8498a06a0 Binary files /dev/null and b/res/drawable/new_contact_actif.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/not_connected_led.png b/res/drawable/not_connected_led.png new file mode 100644 index 000000000..e7617832b Binary files /dev/null and b/res/drawable/not_connected_led.png differ diff --git a/res/drawable/not_secure.png b/res/drawable/not_secure.png new file mode 100644 index 000000000..bf75d1b27 Binary files /dev/null and b/res/drawable/not_secure.png differ diff --git a/res/drawable/numpad_background.png b/res/drawable/numpad_background.png new file mode 100644 index 000000000..062a1eca5 Binary files /dev/null and b/res/drawable/numpad_background.png differ diff --git a/res/drawable/numpad_eight.xml b/res/drawable/numpad_eight.xml new file mode 100644 index 000000000..7f90f5a39 --- /dev/null +++ b/res/drawable/numpad_eight.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_eight_actif.png b/res/drawable/numpad_eight_actif.png new file mode 100644 index 000000000..a3c0d8033 Binary files /dev/null and b/res/drawable/numpad_eight_actif.png differ diff --git a/res/drawable/numpad_eight_over.png b/res/drawable/numpad_eight_over.png new file mode 100644 index 000000000..a40d8ca49 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..62ad90d73 --- /dev/null +++ b/res/drawable/numpad_five.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_five_actif.png b/res/drawable/numpad_five_actif.png new file mode 100644 index 000000000..023eee43b Binary files /dev/null and b/res/drawable/numpad_five_actif.png differ diff --git a/res/drawable/numpad_five_over.png b/res/drawable/numpad_five_over.png new file mode 100644 index 000000000..3dbb9321f 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..5b8d45815 --- /dev/null +++ b/res/drawable/numpad_four.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_four_actif.png b/res/drawable/numpad_four_actif.png new file mode 100644 index 000000000..fa788a745 Binary files /dev/null and b/res/drawable/numpad_four_actif.png differ diff --git a/res/drawable/numpad_four_over.png b/res/drawable/numpad_four_over.png new file mode 100644 index 000000000..0097edc4f 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..b82103179 --- /dev/null +++ b/res/drawable/numpad_nine.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_nine_actif.png b/res/drawable/numpad_nine_actif.png new file mode 100644 index 000000000..594a49d5f Binary files /dev/null and b/res/drawable/numpad_nine_actif.png differ diff --git a/res/drawable/numpad_nine_over.png b/res/drawable/numpad_nine_over.png new file mode 100644 index 000000000..69645647b 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..2c29d616b --- /dev/null +++ b/res/drawable/numpad_one.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_one_actif.png b/res/drawable/numpad_one_actif.png new file mode 100644 index 000000000..07f8d0ecf Binary files /dev/null and b/res/drawable/numpad_one_actif.png differ diff --git a/res/drawable/numpad_one_over.png b/res/drawable/numpad_one_over.png new file mode 100644 index 000000000..21004f314 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..c676b7fc7 --- /dev/null +++ b/res/drawable/numpad_seven.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_seven_actif.png b/res/drawable/numpad_seven_actif.png new file mode 100644 index 000000000..85ea3ddcf Binary files /dev/null and b/res/drawable/numpad_seven_actif.png differ diff --git a/res/drawable/numpad_seven_over.png b/res/drawable/numpad_seven_over.png new file mode 100644 index 000000000..d5252a251 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..64940acdb --- /dev/null +++ b/res/drawable/numpad_sharp.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_sharp_actif.png b/res/drawable/numpad_sharp_actif.png new file mode 100644 index 000000000..c551d9121 Binary files /dev/null and b/res/drawable/numpad_sharp_actif.png differ diff --git a/res/drawable/numpad_sharp_over.png b/res/drawable/numpad_sharp_over.png new file mode 100644 index 000000000..efa63d7e4 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..2c75863dd --- /dev/null +++ b/res/drawable/numpad_six.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_six_actif.png b/res/drawable/numpad_six_actif.png new file mode 100644 index 000000000..5404d14ec Binary files /dev/null and b/res/drawable/numpad_six_actif.png differ diff --git a/res/drawable/numpad_six_over.png b/res/drawable/numpad_six_over.png new file mode 100644 index 000000000..c782b7281 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..9d8b3fb12 --- /dev/null +++ b/res/drawable/numpad_star.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_star_actif.png b/res/drawable/numpad_star_actif.png new file mode 100644 index 000000000..6034e1a99 Binary files /dev/null and b/res/drawable/numpad_star_actif.png differ diff --git a/res/drawable/numpad_star_over.png b/res/drawable/numpad_star_over.png new file mode 100644 index 000000000..9d1b7c65d 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..2e846d9ad --- /dev/null +++ b/res/drawable/numpad_three.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_three_actif.png b/res/drawable/numpad_three_actif.png new file mode 100644 index 000000000..5a489c493 Binary files /dev/null and b/res/drawable/numpad_three_actif.png differ diff --git a/res/drawable/numpad_three_over.png b/res/drawable/numpad_three_over.png new file mode 100644 index 000000000..618070a48 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..759b35ffb --- /dev/null +++ b/res/drawable/numpad_two.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_two_actif.png b/res/drawable/numpad_two_actif.png new file mode 100644 index 000000000..0de47b0bb Binary files /dev/null and b/res/drawable/numpad_two_actif.png differ diff --git a/res/drawable/numpad_two_over.png b/res/drawable/numpad_two_over.png new file mode 100644 index 000000000..3f7cc2363 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..fc9e2facb --- /dev/null +++ b/res/drawable/numpad_zero.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/numpad_zero_actif.png b/res/drawable/numpad_zero_actif.png new file mode 100644 index 000000000..465a3c9f6 Binary files /dev/null and b/res/drawable/numpad_zero_actif.png differ diff --git a/res/drawable/numpad_zero_over.png b/res/drawable/numpad_zero_over.png new file mode 100644 index 000000000..2c6cb21f4 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..5b62217a1 --- /dev/null +++ b/res/drawable/ok.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/ok_actif.png b/res/drawable/ok_actif.png new file mode 100644 index 000000000..7fb188033 Binary files /dev/null and b/res/drawable/ok_actif.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/outgoing_call.png b/res/drawable/outgoing_call.png new file mode 100644 index 000000000..645875ce1 Binary files /dev/null and b/res/drawable/outgoing_call.png differ diff --git a/res/drawable/pause.xml b/res/drawable/pause.xml new file mode 100644 index 000000000..dabbd1e83 --- /dev/null +++ b/res/drawable/pause.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/pause_actif.png b/res/drawable/pause_actif.png new file mode 100644 index 000000000..c6bf04de7 Binary files /dev/null and b/res/drawable/pause_actif.png differ diff --git a/res/drawable/pause_over.png b/res/drawable/pause_over.png new file mode 100644 index 000000000..7289286c2 Binary files /dev/null and b/res/drawable/pause_over.png differ diff --git a/res/drawable/play.xml b/res/drawable/play.xml new file mode 100644 index 000000000..42653fbbf --- /dev/null +++ b/res/drawable/play.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/play_actif.png b/res/drawable/play_actif.png new file mode 100644 index 000000000..f6c266768 Binary files /dev/null and b/res/drawable/play_actif.png differ diff --git a/res/drawable/play_over.png b/res/drawable/play_over.png new file mode 100644 index 000000000..8268d1f8a Binary files /dev/null and b/res/drawable/play_over.png 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/quality_call_0.png b/res/drawable/quality_call_0.png new file mode 100644 index 000000000..7bdaf40ab Binary files /dev/null and b/res/drawable/quality_call_0.png differ diff --git a/res/drawable/quality_call_1.png b/res/drawable/quality_call_1.png new file mode 100644 index 000000000..2cca9b39c Binary files /dev/null and b/res/drawable/quality_call_1.png differ diff --git a/res/drawable/quality_call_2.png b/res/drawable/quality_call_2.png new file mode 100644 index 000000000..adab949fc Binary files /dev/null and b/res/drawable/quality_call_2.png differ diff --git a/res/drawable/quality_call_3.png b/res/drawable/quality_call_3.png new file mode 100644 index 000000000..91118ff60 Binary files /dev/null and b/res/drawable/quality_call_3.png differ diff --git a/res/drawable/raccrocher.xml b/res/drawable/raccrocher.xml new file mode 100644 index 000000000..929411613 --- /dev/null +++ b/res/drawable/raccrocher.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/res/drawable/raccrocher_actif.png b/res/drawable/raccrocher_actif.png new file mode 100644 index 000000000..c84ea15b2 Binary files /dev/null and b/res/drawable/raccrocher_actif.png differ diff --git a/res/drawable/raccrocher_over.png b/res/drawable/raccrocher_over.png new file mode 100644 index 000000000..2c95c5c1a Binary files /dev/null and b/res/drawable/raccrocher_over.png differ diff --git a/res/drawable/secure.png b/res/drawable/secure.png new file mode 100644 index 000000000..0a48c7d14 Binary files /dev/null and b/res/drawable/secure.png differ diff --git a/res/drawable/settings.xml b/res/drawable/settings.xml new file mode 100644 index 000000000..b3e8b8b2e --- /dev/null +++ b/res/drawable/settings.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/drawable/settings_actif.png b/res/drawable/settings_actif.png new file mode 100644 index 000000000..ecf4ab11b Binary files /dev/null and b/res/drawable/settings_actif.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_selectionne.png b/res/drawable/settings_selectionne.png new file mode 100644 index 000000000..1befba3bf Binary files /dev/null and b/res/drawable/settings_selectionne.png differ diff --git a/res/drawable/setup_back.xml b/res/drawable/setup_back.xml new file mode 100644 index 000000000..430299a49 --- /dev/null +++ b/res/drawable/setup_back.xml @@ -0,0 +1,7 @@ + + + + + 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_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..61922945f --- /dev/null +++ b/res/drawable/setup_cancel.xml @@ -0,0 +1,7 @@ + + + + + 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_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_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..79dde1850 --- /dev/null +++ b/res/drawable/setup_next.xml @@ -0,0 +1,7 @@ + + + + + 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/speaker_off.xml b/res/drawable/speaker_off.xml new file mode 100644 index 000000000..3c43342a9 --- /dev/null +++ b/res/drawable/speaker_off.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/res/drawable/speaker_off_actif.png b/res/drawable/speaker_off_actif.png new file mode 100644 index 000000000..5094dd200 Binary files /dev/null and b/res/drawable/speaker_off_actif.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..a91c3de7f --- /dev/null +++ b/res/drawable/speaker_on.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/res/drawable/speaker_on_actif.png b/res/drawable/speaker_on_actif.png new file mode 100644 index 000000000..2f4f58440 Binary files /dev/null and b/res/drawable/speaker_on_actif.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/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..e0e42c09f 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..7afcd0a23 Binary files /dev/null and b/res/drawable/switch_camera_over.png 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_off.xml b/res/drawable/video_off.xml new file mode 100644 index 000000000..55707e63e --- /dev/null +++ b/res/drawable/video_off.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/res/drawable/video_off_actif.png b/res/drawable/video_off_actif.png new file mode 100644 index 000000000..8e80dd7a6 Binary files /dev/null and b/res/drawable/video_off_actif.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..9f8c66d0b --- /dev/null +++ b/res/drawable/video_on.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/res/drawable/video_on_actif.png b/res/drawable/video_on_actif.png new file mode 100644 index 000000000..dde8964d9 Binary files /dev/null and b/res/drawable/video_on_actif.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/wizard_notok.png b/res/drawable/wizard_notok.png new file mode 100644 index 000000000..84813bc2d Binary files /dev/null and b/res/drawable/wizard_notok.png differ diff --git a/res/drawable/wizard_ok.png b/res/drawable/wizard_ok.png new file mode 100644 index 000000000..769986fb7 Binary files /dev/null and b/res/drawable/wizard_ok.png differ diff --git a/res/layout/audio.xml b/res/layout/audio.xml new file mode 100644 index 000000000..b9bc68df0 --- /dev/null +++ b/res/layout/audio.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/chat.xml b/res/layout/chat.xml new file mode 100644 index 000000000..06b77a237 --- /dev/null +++ b/res/layout/chat.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/chatlist.xml b/res/layout/chatlist.xml new file mode 100644 index 000000000..7791dfc6a --- /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..a212e496d --- /dev/null +++ b/res/layout/chatlist_cell.xml @@ -0,0 +1,36 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/contact.xml b/res/layout/contact.xml new file mode 100644 index 000000000..117f9bdcf --- /dev/null +++ b/res/layout/contact.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + \ 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..23720b9bb --- /dev/null +++ b/res/layout/contact_control_row.xml @@ -0,0 +1,42 @@ + + + + + + + + + + \ No newline at end of file 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 e66ce2cd4..6214d38df 100644 --- a/res/layout/dialer.xml +++ b/res/layout/dialer.xml @@ -12,6 +12,7 @@ android:textColor="@android:color/white" android:textSize="22dp" android:background="@drawable/champ_saisie_numero" + android:inputType="textEmailAddress" android:paddingLeft="20dp" android:paddingRight="20dp" android:layout_weight="0.4" diff --git a/res/layout/history.xml b/res/layout/history.xml new file mode 100644 index 000000000..82667e13e --- /dev/null +++ b/res/layout/history.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + \ 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..55b15c396 --- /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..15b31907e --- /dev/null +++ b/res/layout/incall.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file 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..e3ce78e17 --- /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..8b3027f3d --- /dev/null +++ b/res/layout/setup_generic_login.xml @@ -0,0 +1,8 @@ + + + + + \ 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..8b3027f3d --- /dev/null +++ b/res/layout/setup_wizard.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/res/layout/status.xml b/res/layout/status.xml new file mode 100644 index 000000000..08697d7e1 --- /dev/null +++ b/res/layout/status.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/video.xml b/res/layout/video.xml new file mode 100644 index 000000000..36b6dae84 --- /dev/null +++ b/res/layout/video.xml @@ -0,0 +1,29 @@ + + + + + + + + + + \ 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/non_localizable_custom.xml b/res/values/non_localizable_custom.xml index ba9d59ddb..338f18d10 100644 --- a/res/values/non_localizable_custom.xml +++ b/res/values/non_localizable_custom.xml @@ -2,14 +2,14 @@ - test.linphone.org + sip.linphone.org false false false false - false + true false true diff --git a/res/values/strings.xml b/res/values/strings.xml index fae721f0e..bc43eb8ca 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -245,7 +245,7 @@ Password Confirmation Email -Account Wizard +Account Setup Assistant Create Account Cancel An error occurred, try again later. @@ -299,4 +299,18 @@ + + + + + + +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 diff --git a/src/org/linphone/AccountPreferencesActivity.java b/src/org/linphone/AccountPreferencesActivity.java new file mode 100644 index 000000000..813cf7846 --- /dev/null +++ b/src/org/linphone/AccountPreferencesActivity.java @@ -0,0 +1,184 @@ +package org.linphone; +/* +LinphonePreferencesSIPAccountActivity.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. +*/ + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +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.InputType; + +/** + * @author Sylvain Berfini + */ +public class AccountPreferencesActivity extends LinphonePreferencesActivity { + + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.account_preferences); + + PreferenceScreen screen = getPreferenceScreen(); + int n = getIntent().getExtras().getInt("Account", 1); + addExtraAccountPreferencesFields(screen, n); + } + + OnPreferenceChangeListener preferenceChangedListener = new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + preference.setSummary(newValue.toString()); + return true; + } + }; + + private void addExtraAccountPreferencesFields(PreferenceScreen parent, final int n) { + final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + + EditTextPreference username = new EditTextPreference(this); + username.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + username.setTitle(getString(R.string.pref_username)); + username.setPersistent(true); + username.setDialogMessage(getString(R.string.pref_help_username)); + username.setKey(getString(R.string.pref_username_key) + getAccountNumber(n)); + username.setOnPreferenceChangeListener(preferenceChangedListener); + + EditTextPreference password = new EditTextPreference(this); + password.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); + password.setTitle(getString(R.string.pref_passwd)); + password.setPersistent(true); + password.setKey(getString(R.string.pref_passwd_key) + getAccountNumber(n)); + + EditTextPreference domain = new EditTextPreference(this); + domain.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + domain.setTitle(getString(R.string.pref_domain)); + domain.setPersistent(true); + domain.setDialogMessage(getString(R.string.pref_help_domain)); + domain.setKey(getString(R.string.pref_domain_key) + getAccountNumber(n)); + domain.setOnPreferenceChangeListener(preferenceChangedListener); + + EditTextPreference proxy = new EditTextPreference(this); + proxy.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + proxy.setTitle(getString(R.string.pref_proxy)); + proxy.setPersistent(true); + proxy.setKey(getString(R.string.pref_proxy_key) + getAccountNumber(n)); + proxy.setOnPreferenceChangeListener(preferenceChangedListener); + + CheckBoxPreference outboundProxy = new CheckBoxPreference(this); + outboundProxy.setTitle(getString(R.string.pref_enable_outbound_proxy)); + outboundProxy.setPersistent(true); + outboundProxy.setKey(getString(R.string.pref_enable_outbound_proxy_key) + getAccountNumber(n)); + + final CheckBoxPreference disable = new CheckBoxPreference(this); + disable.setTitle(getString(R.string.pref_disable_account)); + disable.setPersistent(true); + disable.setKey(getString(R.string.pref_disable_account_key) + getAccountNumber(n)); + + final Preference delete = new Preference(this); + delete.setTitle(R.string.pref_delete_account); + delete.setOnPreferenceClickListener(new OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + int nbAccounts = prefs.getInt(getString(R.string.pref_extra_accounts), 1); + SharedPreferences.Editor editor = prefs.edit(); + + for (int i = n; i < nbAccounts - 1; i++) { + editor.putString(getString(R.string.pref_username_key) + getAccountNumber(i), prefs.getString(getString(R.string.pref_username_key) + getAccountNumber(i+1), null)); + editor.putString(getString(R.string.pref_passwd_key) + getAccountNumber(i), prefs.getString(getString(R.string.pref_passwd_key) + getAccountNumber(i+1), null)); + editor.putString(getString(R.string.pref_domain_key) + getAccountNumber(i), prefs.getString(getString(R.string.pref_domain_key) + getAccountNumber(i+1), null)); + editor.putString(getString(R.string.pref_proxy_key) + getAccountNumber(i), prefs.getString(getString(R.string.pref_proxy_key) + getAccountNumber(i+1), null)); + editor.putBoolean(getString(R.string.pref_enable_outbound_proxy_key) + getAccountNumber(i), prefs.getBoolean(getString(R.string.pref_enable_outbound_proxy_key) + getAccountNumber(i+1), false)); + editor.putBoolean(getString(R.string.pref_disable_account_key) + getAccountNumber(i), prefs.getBoolean(getString(R.string.pref_disable_account_key) + getAccountNumber(i+1), false)); + } + + int lastAccount = nbAccounts - 1; + editor.putString(getString(R.string.pref_username_key) + getAccountNumber(lastAccount), null); + editor.putString(getString(R.string.pref_passwd_key) + getAccountNumber(lastAccount), null); + editor.putString(getString(R.string.pref_domain_key) + getAccountNumber(lastAccount), null); + editor.putString(getString(R.string.pref_proxy_key) + getAccountNumber(lastAccount), null); + editor.putBoolean(getString(R.string.pref_enable_outbound_proxy_key) + getAccountNumber(lastAccount), false); + editor.putBoolean(getString(R.string.pref_disable_account_key) + getAccountNumber(lastAccount), false); + + int defaultAccount = prefs.getInt(getString(R.string.pref_default_account), 0); + if (defaultAccount > n) { + editor.putInt(getString(R.string.pref_default_account), defaultAccount - 1); + } + + editor.putInt(getString(R.string.pref_extra_accounts), nbAccounts - 1); + editor.commit(); + AccountPreferencesActivity.this.finish(); + return true; + } + }); + + CheckBoxPreference mainAccount = new CheckBoxPreference(this); + mainAccount.setTitle(R.string.pref_default_account_title); + mainAccount.setOnPreferenceClickListener(new OnPreferenceClickListener() + { + public boolean onPreferenceClick(Preference preference) { + + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(getString(R.string.pref_default_account), n); + editor.commit(); + delete.setEnabled(false); + disable.setEnabled(false); + disable.setChecked(false); + preference.setEnabled(false); + return true; + } + }); + + mainAccount.setChecked(prefs.getInt(getString(R.string.pref_default_account), 0) == n); + mainAccount.setEnabled(!mainAccount.isChecked()); + delete.setEnabled(prefs.getInt(getString(R.string.pref_default_account), 0) != n); + disable.setEnabled(prefs.getInt(getString(R.string.pref_default_account), 0) != n); + + PreferenceCategory category = new PreferenceCategory(this); + category.setTitle(getString(R.string.pref_sipaccount)); + parent.addPreference(category); + category.addPreference(username); + category.addPreference(password); + category.addPreference(domain); + + category = new PreferenceCategory(this); + category.setTitle(getString(R.string.pref_advanced)); + parent.addPreference(category); + category.addPreference(proxy); + category.addPreference(outboundProxy); + category.addPreference(disable); + category.addPreference(mainAccount); + category.addPreference(delete); + + username.setSummary(username.getText()); + domain.setSummary(domain.getText()); + proxy.setSummary("".equals(proxy.getText()) || (proxy.getText() == null) ? getString(R.string.pref_help_proxy) : proxy.getText()); + outboundProxy.setSummary(getString(R.string.pref_help_outbound_proxy)); + } + + private String getAccountNumber(int n) { + if (n > 0) + return Integer.toString(n); + else + return ""; + } +} \ No newline at end of file diff --git a/src/org/linphone/AudioCallFragment.java b/src/org/linphone/AudioCallFragment.java new file mode 100644 index 000000000..b45e8c983 --- /dev/null +++ b/src/org/linphone/AudioCallFragment.java @@ -0,0 +1,82 @@ +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.LinphoneCoreFactory; + +import android.app.Activity; +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.TextView; + +/** + * @author Sylvain Berfini + */ +public class AudioCallFragment extends Fragment { + private static AudioCallFragment instance; +// private Chronometer timer; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + instance = this; + View view = inflater.inflate(R.layout.audio, container, false); +// timer = (Chronometer) view.findViewById(R.id.callTimer); + + LinphoneCall currentCall; + do { + currentCall = LinphoneManager.getLc().getCurrentCall(); + } while (currentCall == null); + + String sipUri = currentCall.getRemoteAddress().asStringUriOnly(); + LinphoneAddress lAddress = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri); + Uri pictureUri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, view.getContext().getContentResolver()); + + TextView contact = (TextView) view.findViewById(R.id.contactNameOrNumber); + contact.setText(lAddress.getDisplayName() == null ? sipUri : lAddress.getDisplayName()); + + ImageView contactPicture = (ImageView) view.findViewById(R.id.contactPicture); + if (pictureUri != null) { + LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture, Uri.parse(pictureUri.toString()), R.drawable.unknown_small); + } + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + // Just to be sure we have incall controls + InCallActivity.instance().setCallControlsVisibleAndRemoveCallbacks(); + } + + /** + * @return null if not ready yet + */ + public static AudioCallFragment instance() { + return instance; + } +} diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java new file mode 100644 index 000000000..bbcbb55ed --- /dev/null +++ b/src/org/linphone/ChatFragment.java @@ -0,0 +1,143 @@ +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.LinphoneOnMessageReceived; +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, LinphoneOnMessageReceived { + 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); + contactName.setText(name == null ? sipUri : 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); + + previousMessageID = -1; + for (ChatMessage msg : messagesList) { + displayMessage(msg.getId(), msg.getMessage(), 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 boolean isIncoming, final RelativeLayout layout) { + mHandler.post(new Runnable() { + @Override + public void run() { + BubbleChat bubble = new BubbleChat(layout.getContext(), id, message, 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); + } + } + + @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, false, messagesLayout); + scrollToEnd(); + } + } + + private void scrollToEnd() { + mHandler.post(new Runnable() { + @Override + public void run() { + messagesScrollView.fullScroll(View.FOCUS_DOWN); + } + }); + } + + @Override + public void onMessageReceived(LinphoneAddress from, String message) { + displayMessage(previousMessageID + 1, message, true, messagesLayout); + scrollToEnd(); + } +} diff --git a/src/org/linphone/ChatListFragment.java b/src/org/linphone/ChatListFragment.java new file mode 100644 index 000000000..9a7082882 --- /dev/null +++ b/src/org/linphone/ChatListFragment.java @@ -0,0 +1,163 @@ +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); + 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/Contact.java b/src/org/linphone/Contact.java new file mode 100644 index 000000000..e456bcc54 --- /dev/null +++ b/src/org/linphone/Contact.java @@ -0,0 +1,69 @@ +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.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 photo; + private List numerosOrAddresses; + + public Contact(String id, String name) { + super(); + this.id = id; + this.name = name; + this.photo = null; + } + + public Contact(String id, String name, Uri photo) { + super(); + this.id = id; + this.name = name; + this.photo = photo; + } + + public String getID() { + return id; + } + + public String getName() { + return name; + } + + public Uri 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..860a79621 --- /dev/null +++ b/src/org/linphone/ContactFragment.java @@ -0,0 +1,97 @@ +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.getPhoto(), 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 numeroOrAddress : contact.getNumerosOrAddresses()) { + View v = inflater.inflate(R.layout.contact_control_row, null); + + ((TextView) v.findViewById(R.id.numeroOrAddress)).setText(numeroOrAddress); + + v.findViewById(R.id.dial).setOnClickListener(dialListener); + v.findViewById(R.id.dial).setTag(numeroOrAddress); + + v.findViewById(R.id.chat).setOnClickListener(chatListener); + v.findViewById(R.id.chat).setTag(numeroOrAddress); + + 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().setAddressAndGoToDialer(v.getTag().toString(), contact.getName(), contact.getPhoto()); + } + }; + } + + public OnClickListener getChatListener() { + return new OnClickListener() { + @Override + public void onClick(View v) { + LinphoneActivity.instance().displayChat(v.getTag().toString()); + } + }; + } +} diff --git a/src/org/linphone/ContactsFragment.java b/src/org/linphone/ContactsFragment.java new file mode 100644 index 000000000..f0bd86288 --- /dev/null +++ b/src/org/linphone/ContactsFragment.java @@ -0,0 +1,215 @@ +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 android.content.ContentUris; +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; + + @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 = ContactHelper.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 onResume() { + super.onResume(); + if (LinphoneActivity.isInstanciated()) { + LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACTS); + } + + cursor = getActivity().getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, ContactsContract.Contacts.DISPLAY_NAME + " IS NOT NULL", null, ContactsContract.Contacts.DISPLAY_NAME + " ASC"); + if (contactsList.getAdapter() == null) { + contactsList.setAdapter(new ContactsListAdapter()); + contactsList.setFastScrollEnabled(true); + } + + contactsList.setSelectionFromTop(lastKnownPosition, 0); + } + + class ContactsListAdapter extends BaseAdapter implements SectionIndexer { + private AlphabetIndexer indexer; + private int margin; + private Bitmap bitmapUnknown; + + ContactsListAdapter() { + indexer = new AlphabetIndexer(cursor, cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME), " 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) { + cursor.moveToFirst(); + boolean success = cursor.move(position); + if (!success) + return null; + + String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); + String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); + Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(id)); + Uri photo = Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY); + + InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(getActivity().getContentResolver(), person); + Contact contact; + if (input == null) { + contact = new Contact(id, name); + } + else { + contact = new Contact(id, name, photo); + } + + contact.setNumerosOrAddresses(ContactHelper.extractContactNumbersAndAddresses(contact.getID(), getActivity().getContentResolver())); + + return contact; + } + + 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 = (Contact) getItem(position); + + 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.setImageURI(contact.getPhoto()); + } 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/DialerFragment.java b/src/org/linphone/DialerFragment.java new file mode 100644 index 000000000..b8ca20440 --- /dev/null +++ b/src/org/linphone/DialerFragment.java @@ -0,0 +1,130 @@ +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.appeler); + } + + 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); + mAddContact.setImageResource(R.drawable.cancel); + mAddContact.setOnClickListener(cancelListener); + } else { + mCall.setImageResource(R.drawable.appeler); + mAddContact.setImageResource(R.drawable.add_contact); + mAddContact.setOnClickListener(addContactListener); + } + } +} diff --git a/src/org/linphone/FragmentsAvailable.java b/src/org/linphone/FragmentsAvailable.java new file mode 100644 index 000000000..09e74f760 --- /dev/null +++ b/src/org/linphone/FragmentsAvailable.java @@ -0,0 +1,48 @@ +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 this == HISTORY_DETAIL || + this == HISTORY || + this == CONTACT || + this == CONTACTS || + this == CHATLIST || + this == CHAT; + } + + public boolean shouldAnimate() { + return this == HISTORY_DETAIL || + this == CONTACT || + this == CHAT; + } +} diff --git a/src/org/linphone/HistoryDetailFragment.java b/src/org/linphone/HistoryDetailFragment.java new file mode 100644 index 000000000..e90e7fe14 --- /dev/null +++ b/src/org/linphone/HistoryDetailFragment.java @@ -0,0 +1,104 @@ +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 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); + 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().setAddressAndGoToDialer(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 = ContactHelper.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..e6b1bff47 --- /dev/null +++ b/src/org/linphone/HistoryFragment.java @@ -0,0 +1,214 @@ +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.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 { + + CallHistoryAdapter(Context aContext) { + + if (onlyDisplayMissedCalls) { + List missedCalls = new ArrayList(); + for (LinphoneCallLog log : mLogs) { + if (log.getStatus() == CallStatus.Missed) { + missedCalls.add(log); + } + } + mLogs = missedCalls; + } + } + 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 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.setImageResource(R.drawable.missed_call); + } else { + callDirection.setImageResource(R.drawable.incoming_call); + } + } else { + address = log.getTo(); + callDirection.setImageResource(R.drawable.outgoing_call); + } + + LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, view.getContext().getContentResolver()); + String displayName = address.getDisplayName(); + String sipUri = address.asStringUriOnly(); + + if (displayName == null) { + contact.setText(sipUri); + } 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..0025fd94d --- /dev/null +++ b/src/org/linphone/InCallActivity.java @@ -0,0 +1,385 @@ +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.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 : Speaker +//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; + private StatusFragment status; + private AudioCallFragment audioCallFragment; + private boolean isSpeakerEnabled, isMicMuted, isVideoEnabled; + 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; + } + + isSpeakerEnabled = LinphoneManager.getInstance().isSpeakerOn(); + isMicMuted = LinphoneManager.getLc().isMicMuted(); + isVideoEnabled = getIntent().getBooleanExtra("VideoEnabled", false); + initUI(); + + Fragment callFragment; + if (isVideoEnabled) { + callFragment = new VideoCallFragment(); + } else { + callFragment = new AudioCallFragment(); + audioCallFragment = (AudioCallFragment) callFragment; + } + 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); + micro = (ImageView) findViewById(R.id.micro); + micro.setOnClickListener(this); + speaker = (ImageView) findViewById(R.id.speaker); + speaker.setOnClickListener(this); + addCall = (ImageView) findViewById(R.id.addCall); + addCall.setOnClickListener(this); + pause = (ImageView) findViewById(R.id.pause); + pause.setOnClickListener(this); + hangUp = (ImageView) findViewById(R.id.hangUp); + hangUp.setOnClickListener(this); + dialer = (ImageView) findViewById(R.id.dialer); + dialer.setOnClickListener(this); + + mControlsLayout = (LinearLayout) findViewById(R.id.menu); + + if (isVideoEnabled) { + video.setImageResource(R.drawable.video_off); + } + if (isSpeakerEnabled) { + speaker.setImageResource(R.drawable.speaker_off_over); + } + if (isMicMuted) { + 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) { + + } + } + + + 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(); + + video.setImageResource(R.drawable.video_on); + setCallControlsVisibleAndRemoveCallbacks(); + + } else { + if (!call.getCurrentParamsCopy().getVideoEnabled()) { + LinphoneManager.getInstance().addVideo(); + } + + replaceFragmentAudioByVideo(); + video.setImageResource(R.drawable.video_off); + displayVideoCallControlsIfHidden(); + } + } + }); + } + + private void replaceFragmentVideoByAudio() { + audioCallFragment = new AudioCallFragment(); + + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragmentContainer, audioCallFragment); + transaction.commit(); + } + + private void replaceFragmentAudioByVideo() { + VideoCallFragment videoCallFragment = new VideoCallFragment(); + + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragmentContainer, videoCallFragment); + transaction.commitAllowingStateLoss(); + } + + private void toogleMicro() { + LinphoneCore lc = LinphoneManager.getLc(); + isMicMuted = !isMicMuted; + lc.muteMic(isMicMuted); + if (isMicMuted) { + micro.setImageResource(R.drawable.micro_on); + } else { + micro.setImageResource(R.drawable.micro_off); + } + } + + private void toogleSpeaker() { + isSpeakerEnabled = !isSpeakerEnabled; + if (isSpeakerEnabled) { + LinphoneManager.getInstance().routeAudioToSpeaker(); + speaker.setImageResource(R.drawable.speaker_off); + } else { + LinphoneManager.getInstance().routeAudioToReceiver(); + speaker.setImageResource(R.drawable.speaker_on); + } + } + + private void pause() { + LinphoneCore lc = LinphoneManager.getLc(); + LinphoneCall call = lc.getCurrentCall(); + if (call != null && isCallRunning(call)) { + lc.pauseCall(call); + pause.setImageResource(R.drawable.play); + } 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); + } + } + } + + 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); + } 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); + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + } + }); + mControlsLayout.startAnimation(animation); + } + } + + 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); + } 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); + } + }); + mControlsLayout.startAnimation(animation); + } + } + }, SECONDS_BEFORE_HIDING_CONTROLS); + } + } + + public void setCallControlsVisibleAndRemoveCallbacks() { + if (controlsHandler != null && mControls != null) { + controlsHandler.removeCallbacks(mControls); + mControls = null; + } + + mControlsLayout.setVisibility(View.VISIBLE); + } + + 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; + } + + @Override + public void onCallStateChanged(LinphoneCall call, State state, + String message) { + if (LinphoneManager.getLc().getCallsNb() == 0) { + finish(); + } + + if (state == State.StreamsRunning) { + boolean isVideoEnabledInCall = call.getCurrentParamsCopy().getVideoEnabled(); + if (isVideoEnabledInCall != isVideoEnabled) { + isVideoEnabled = isVideoEnabledInCall; + switchVideo(isVideoEnabled); + } + } + } + + @Override + public void onCallEncryptionChanged(LinphoneCall call, boolean encrypted, + String authenticationToken) { + if (status != null) { + status.setEncryption(true); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (isVideoEnabled) { + displayVideoCallControlsIfHidden(); + } else { + setCallControlsVisibleAndRemoveCallbacks(); + } + } + + @Override + protected void onPause() { + super.onPause(); + + setCallControlsVisibleAndRemoveCallbacks(); + } +} diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 58eb4a174..2f4a99437 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -36,12 +36,15 @@ 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.setup.SetupActivity; import android.app.Activity; import android.content.Intent; +import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.app.Fragment.SavedState; import android.support.v4.app.FragmentActivity; @@ -62,6 +65,7 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene LinphoneOnRegistrationStateChangedListener { public static final String PREF_FIRST_LAUNCH = "pref_first_launch"; private static final int SETTINGS_ACTIVITY = 123; + private static final int FIRST_LOGIN_ACTIVITY = 101; private static final int callActivity = 19; private static LinphoneActivity instance; private StatusFragment statusFragment; @@ -86,8 +90,27 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + 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; + } + + 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); + } + setContentView(R.layout.main); - instance = this; + initButtons(); + + if (LinphoneManager.isInstanciated()) { + LinphoneManager.addListener(this); + } if (findViewById(R.id.fragmentContainer) != null) { if (savedInstanceState != null) { @@ -99,16 +122,12 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene getSupportFragmentManager().beginTransaction() .add(R.id.fragmentContainer, dialerFragment).commit(); currentFragment = FragmentsAvailable.DIALER; - - initButtons(); } - if (LinphoneManager.isInstanciated()) { - LinphoneManager.addListener(this); - } - int missedCalls = LinphoneManager.getLc().getMissedCallsCount(); displayMissedCalls(missedCalls); + + instance = this; } private void initButtons() { @@ -179,7 +198,7 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); if (currentFragment.shouldAddToBackStack()) { - if (!getResources().getBoolean(R.bool.disable_animations)) { + if (!getResources().getBoolean(R.bool.disable_animations) && currentFragment.shouldAnimate()) { 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); } transaction.addToBackStack("Add to back stack"); @@ -334,6 +353,9 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene public void updateStatusFragment(StatusFragment fragment) { statusFragment = fragment; + if (LinphoneManager.getLc().getDefaultProxyConfig() != null) { + statusFragment.registrationStateChanged(LinphoneManager.getLc().getDefaultProxyConfig().getState()); + } } public ArrayList getChatList() { @@ -344,24 +366,29 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene } public List getChatMessages(String correspondent) { - if (chatStorage != null) { - return chatStorage.getMessages(correspondent); + if (chatStorage == null) { + chatStorage = new ChatStorage(this); } - return null; + + return chatStorage.getMessages(correspondent); } public void removeFromChatList(String sipUri) { - if (chatStorage != null) { - chatStorage.removeDiscussion(sipUri); + if (chatStorage == null) { + chatStorage = new ChatStorage(this); } + + chatStorage.removeDiscussion(sipUri); } @Override public void onMessageReceived(LinphoneAddress from, String message) { - if (chatStorage != null) { - chatStorage.saveMessage(from.asStringUriOnly(), "", 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); @@ -369,14 +396,16 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene if (LinphoneService.isReady()) { LinphoneUtils.findUriPictureOfContactAndSetDisplayName(from, getContentResolver()); - LinphoneService.instance().displayMessageNotification(from.getDisplayName(), message); + LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), from.getDisplayName(), message); } } public void onMessageSent(String to, String message) { - if (chatStorage != null) { - chatStorage.saveMessage("", to, message); + if (chatStorage == null) { + chatStorage = new ChatStorage(this); } + + chatStorage.saveMessage("", to, message); Log.d("Message sent to " + to + ": " + message); } @@ -519,6 +548,9 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene protected void onResume() { super.onResume(); + if (chatStorage != null) { + chatStorage.close(); + } chatStorage = new ChatStorage(this); } @@ -527,6 +559,19 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene super.onPause(); chatStorage.close(); + chatStorage = null; + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Bundle extras = intent.getExtras(); + if (extras != null && extras.getBoolean("GoToChat", false)) { + LinphoneService.instance().removeMessageNotification(); + String sipUri = extras.getString("ChatContactSipUri"); + displayChat(sipUri); + } } } diff --git a/src/org/linphone/LinphoneService.java b/src/org/linphone/LinphoneService.java index 3cbebe561..0b9e2105b 100644 --- a/src/org/linphone/LinphoneService.java +++ b/src/org/linphone/LinphoneService.java @@ -101,6 +101,7 @@ public final class LinphoneService extends Service implements LinphoneServiceLis private Notification mNotif; private Notification mIncallNotif; private Notification mMsgNotif; + private int mMsgNotifCount; private PendingIntent mNotifContentIntent; private String mNotificationTitle; @@ -139,7 +140,7 @@ public final class LinphoneService extends Service implements LinphoneServiceLis mNotif.flags |= Notification.FLAG_ONGOING_EVENT; Intent notifIntent = new Intent(this, LinphoneActivity.class); - 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); @@ -232,19 +233,41 @@ public final class LinphoneService extends Service implements LinphoneServiceLis } } - public void displayMessageNotification(String from, String message) { + 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 (mMsgNotif == null) { + mMsgNotifCount = 1; mMsgNotif = new Notification(); - mMsgNotif.icon = R.drawable.chaticon; + mMsgNotif.icon = R.drawable.chat_icon_over; mMsgNotif.iconLevel = 0; - mMsgNotif.when=System.currentTimeMillis(); + mMsgNotif.when = System.currentTimeMillis(); mMsgNotif.flags &= Notification.FLAG_ONGOING_EVENT; - String title = "New message from %s :".replace("%s", from); - mMsgNotif.setLatestEventInfo(this, title, message, mNotifContentIntent); - notifyWrapper(MESSAGE_NOTIF_ID, mMsgNotif); + 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}; @@ -391,6 +414,7 @@ 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(); } diff --git a/src/org/linphone/PreferencesActivity.java b/src/org/linphone/PreferencesActivity.java new file mode 100644 index 000000000..e7b0c1caf --- /dev/null +++ b/src/org/linphone/PreferencesActivity.java @@ -0,0 +1,535 @@ +/* +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 ADD_ACCOUNT_SETTINGS_ID = 2; + private static final int WIZARD_SETTINGS_ID = 3; + private static final int CAMERA_SETTINGS_ID = 7; + 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); + } + } + + 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(PreferencesActivity.this, AccountPreferencesActivity.class); + startActivityForResult(i, ADD_SIP_ACCOUNT); + return true; + } + }); + } + + 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); + } + + 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) { + 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(); + + // 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); + } + + 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..1ed8ce8c8 --- /dev/null +++ b/src/org/linphone/StatusFragment.java @@ -0,0 +1,172 @@ +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.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; + } + } + + public void registrationStateChanged(final RegistrationState state) { + if (!isAttached) + return; + + mHandler.post(new Runnable() { + @Override + public void run() { + if (state == RegistrationState.RegistrationOk) { + statusLed.setImageResource(R.drawable.connected_led); + statusText.setText(getString(R.string.status_connected)); + } else { + statusLed.setImageResource(R.drawable.not_connected_led); + statusText.setText(getString(R.string.status_not_connected)); + } + } + }); + } + + 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.quality_call_3); + } else if (quality >= 3) // Average quality + { + callQuality.setImageResource( + R.drawable.quality_call_2); + } else if (quality >= 2) // Low quality + { + callQuality.setImageResource( + R.drawable.quality_call_1); + } else if (quality >= 1) // Very low quality + { + callQuality.setImageResource( + R.drawable.quality_call_1); + } else // Worst quality + { + callQuality.setImageResource( + R.drawable.quality_call_0); + } + } + + @Override + public void onResume() { + super.onResume(); + + if (isInCall) { + startCallQuality(); + } + } + + @Override + public void onPause() { + super.onPause(); + + if (mCallQualityUpdater != null) { + refreshHandler.removeCallbacks(mCallQualityUpdater); + mCallQualityUpdater = null; + } + } + + public void setEncryption(boolean b) { + if (encryption != null) { + //TODO + } + } +} diff --git a/src/org/linphone/VideoCallFragment.java b/src/org/linphone/VideoCallFragment.java new file mode 100644 index 000000000..fcda06aed --- /dev/null +++ b/src/org/linphone/VideoCallFragment.java @@ -0,0 +1,183 @@ +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.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.OnClickListener; +import android.view.View.OnTouchListener; +import android.view.ViewGroup; +import android.widget.ImageView; + +//FIXME : preview gone after coming back from audio only +/** + * @author Sylvain Berfini + */ +public class VideoCallFragment extends Fragment { + private static VideoCallFragment instance; + private WakeLock mWakeLock; + private SurfaceView mVideoView; + private SurfaceView mCaptureView; + private ImageView switchCamera; + private AndroidVideoWindowImpl androidVideoWindowImpl; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + instance = this; + View view = inflater.inflate(R.layout.video, container, false); + + switchCamera = (ImageView) view.findViewById(R.id.switchCamera); + switchCamera.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + switchCamera(); + } + }); + + 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 + } + + private void switchCamera() { + 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); + } + } + + @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/core/LinphoneCoreImpl.java b/src/org/linphone/core/LinphoneCoreImpl.java index 75e885253..f732782d9 100644 --- a/src/org/linphone/core/LinphoneCoreImpl.java +++ b/src/org/linphone/core/LinphoneCoreImpl.java @@ -710,10 +710,18 @@ class LinphoneCoreImpl implements LinphoneCore { } public void removeCallLog(LinphoneCallLog log) { - removeCallLog(nativePtr, log.getNativePtr()); + removeCallLog(nativePtr, ((LinphoneCallLogImpl) log).getNativePtr()); } 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); + } } diff --git a/src/org/linphone/setup/GenericLoginFragment.java b/src/org/linphone/setup/GenericLoginFragment.java new file mode 100644 index 000000000..9dc752606 --- /dev/null +++ b/src/org/linphone/setup/GenericLoginFragment.java @@ -0,0 +1,38 @@ +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; +/** + * @author Sylvain Berfini + */ +public class GenericLoginFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.setup_generic_login, container, false); + + return view; + } +} diff --git a/src/org/linphone/setup/LinphoneLoginFragment.java b/src/org/linphone/setup/LinphoneLoginFragment.java new file mode 100644 index 000000000..5f00d8c6c --- /dev/null +++ b/src/org/linphone/setup/LinphoneLoginFragment.java @@ -0,0 +1,65 @@ +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().getApplicationContext(), 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..c63e4b2c5 --- /dev/null +++ b/src/org/linphone/setup/SetupActivity.java @@ -0,0 +1,172 @@ +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.FragmentManager; +import android.support.v4.app.FragmentTransaction; +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("Add to back stack"); + getSupportFragmentManager().popBackStack("Add to back stack", FragmentManager.POP_BACK_STACK_INCLUSIVE); + 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) { + MenuFragment fragment = new MenuFragment(); + changeFragment(fragment); + currentFragment = SetupFragments.MENU; + + next.setVisibility(View.GONE); + back.setVisibility(View.VISIBLE); + } else if (id == R.id.setup_back) { + 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; + } + } + } + + public void logIn(String username, String password, String domain) { + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0); + + writePreference(R.string.pref_username_key, username); + writePreference(R.string.pref_passwd_key, password); + writePreference(R.string.pref_domain_key, domain); + writePreference(R.string.pref_extra_accounts, 1); + + 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(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; + } +} diff --git a/src/org/linphone/setup/SetupFragments.java b/src/org/linphone/setup/SetupFragments.java new file mode 100644 index 000000000..0b19f3559 --- /dev/null +++ b/src/org/linphone/setup/SetupFragments.java @@ -0,0 +1,29 @@ +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, + 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/WizardFragment.java b/src/org/linphone/setup/WizardFragment.java new file mode 100644 index 000000000..e02c2a22c --- /dev/null +++ b/src/org/linphone/setup/WizardFragment.java @@ -0,0 +1,391 @@ +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.PreferencesActivity; +import org.linphone.R; + +import android.app.AlertDialog; +import android.content.SharedPreferences; +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.ViewGroup; +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; +/** + * @author Sylvain Berfini + */ +public class WizardFragment extends Fragment { + private Handler mHandler = new Handler(); + + private boolean usernameOk = false; + private boolean passwordOk = false; + private boolean emailOk = false; + private AlertDialog wizardDialog; + private Button createAccount; + private TextView errorMessage; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.setup_wizard, container, false); + + return view; + } + +// protected Dialog onCreateDialog (int id) { +// if (id == WIZARD_ID) { +// AlertDialog.Builder builder = new AlertDialog.Builder(PreferencesActivity.this); +// LayoutInflater inflater = LayoutInflater.from(PreferencesActivity.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(PreferencesActivity.this); +// builder.setTitle(R.string.wizard_confirmation); +// +// final LayoutInflater inflater = LayoutInflater.from(PreferencesActivity.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.wizard_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.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("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); +// PreferencesActivity.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) { +// 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", username, password, email, suscribe ? 1 : 0); +// } +// 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); +// } +// +// 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); +// } +// } +// } +// } +} diff --git a/src/org/linphone/ui/BubbleChat.java b/src/org/linphone/ui/BubbleChat.java new file mode 100644 index 000000000..5df6d5e29 --- /dev/null +++ b/src/org/linphone/ui/BubbleChat.java @@ -0,0 +1,66 @@ +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 org.linphone.R; + +import android.content.Context; +import android.graphics.Color; +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, 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.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + messageView.setText(message); + messageView.setTextColor(Color.BLACK); + + view.setId(id); + view.setLayoutParams(layoutParams); + view.addView(messageView); + } + + public View getView() { + return view; + } +} diff --git a/src/org/linphone/ui/SlidingTab.java b/src/org/linphone/ui/SlidingTab.java index 3ac07b65a..3409e1df1 100644 --- a/src/org/linphone/ui/SlidingTab.java +++ b/src/org/linphone/ui/SlidingTab.java @@ -188,7 +188,7 @@ public class SlidingTab extends ViewGroup { tab = new ImageView(parent.getContext()); tab.setImageResource(iconId); tab.setBackgroundResource(tabId); - tab.setScaleType(ScaleType.CENTER); + tab.setScaleType(ScaleType.FIT_CENTER); tab.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); @@ -449,13 +449,13 @@ public class SlidingTab extends ViewGroup { mOrientation = a.getInt(org.linphone.R.styleable.SlidingTab_orientation, HORIZONTAL); a.recycle(); mLeftSlider = new Slider(this, - R.drawable.startcall, + R.drawable.call_answer_default, 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.endcall, + R.drawable.call_refused_icon, R.drawable.jog_tab_right_decline, R.drawable.jog_tab_bar_right_decline, R.drawable.jog_tab_target_red diff --git a/submodules/linphone b/submodules/linphone index 80e4341e0..9e3835ff1 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 80e4341e05c2410d4b3e64ac8c2b997910ef7075 +Subproject commit 9e3835ff16a7f5fdaf02e7e767bb9de01850e487