Merge branch 'master' into dev_phonenumber
Conflicts: src/org/linphone/LinphoneActivity.java
This commit is contained in:
commit
995b1cd323
50 changed files with 1210 additions and 2399 deletions
15
README
15
README
|
@ -7,8 +7,8 @@ COMPILATION INSTRUCTIONS
|
||||||
|
|
||||||
To build liblinphone for Android, you must:
|
To build liblinphone for Android, you must:
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
0) download the Android sdk with platform-tools and tools updated to latest revision (at least API 16 is needed), then add both 'tools' and 'platform-tools' folders in your path.
|
0) download the Android sdk (API 23 at least) with platform-tools and tools updated to latest revision, then add both 'tools' and 'platform-tools' folders in your path.
|
||||||
1) download the Android ndk (version r11) from google and add it to your path (no symlink !!!).
|
1) download the Android ndk (version r11c or 12b) from google and add it to your path (no symlink !!!).
|
||||||
2) install yasm, nasm, ant, python, cmake and vim-common
|
2) install yasm, nasm, ant, python, cmake and vim-common
|
||||||
On 64 bits linux systems you'll need the ia32-libs package
|
On 64 bits linux systems you'll need the ia32-libs package
|
||||||
With the latest Debian (multiarch), you need this:
|
With the latest Debian (multiarch), you need this:
|
||||||
|
@ -27,11 +27,12 @@ To build liblinphone for Android, you must:
|
||||||
$ make mediastreamer2-sdk
|
$ make mediastreamer2-sdk
|
||||||
8) (Optional) To generate a signed apk to publish on the Google Play, run
|
8) (Optional) To generate a signed apk to publish on the Google Play, run
|
||||||
$ make release
|
$ make release
|
||||||
Make sure you filled the ant.properties values for version.name, key.store and key.alias in order to correctly sign the generated apk.
|
Make sure you filled the ant.properties values for version.name, key.store and key.alias in order to correctly sign the generated apk.
|
||||||
You also may want to create a file name ant_password.properties with the following:
|
You also may want to create a file name ant_password.properties with the following:
|
||||||
key.store.password=[your_password]
|
key.store.password=[your_password]
|
||||||
key.alias.password=[your_password]
|
key.alias.password=[your_password]
|
||||||
If you don't, the passwords will be asked at the signing phase.
|
If you don't, the passwords will be asked at the signing phase.
|
||||||
|
9) (Optional) Once you compiled the libraries succesfully with 'make', you can reduce the compilation time using 'make quick': it will only generate a new APK from java files.
|
||||||
|
|
||||||
To run the tutorials:
|
To run the tutorials:
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
</condition>
|
</condition>
|
||||||
<exec executable="bash" unless:set="has.crashed">
|
<exec executable="bash" unless:set="has.crashed">
|
||||||
<arg value="-c"/>
|
<arg value="-c"/>
|
||||||
<arg value="adb shell run-as org.linphone.tester cat /data/data/org.linphone.tester/files/junit-report.xml > liblinphone-junit-report.xml"/>
|
<arg value="adb shell cat /data/data/org.linphone.tester/files/junit-report.xml > liblinphone-junit-report.xml"/>
|
||||||
</exec>
|
</exec>
|
||||||
|
|
||||||
<zip destfile="${archive.name}.zip">
|
<zip destfile="${archive.name}.zip">
|
||||||
|
|
|
@ -128,8 +128,9 @@
|
||||||
<ListView
|
<ListView
|
||||||
android:id="@+id/chat_message_list"
|
android:id="@+id/chat_message_list"
|
||||||
android:divider="@android:color/transparent"
|
android:divider="@android:color/transparent"
|
||||||
|
android:choiceMode="multipleChoice"
|
||||||
android:stackFromBottom="true"
|
android:stackFromBottom="true"
|
||||||
android:transcriptMode="alwaysScroll"
|
android:transcriptMode="normal"
|
||||||
android:dividerHeight="10dp"
|
android:dividerHeight="10dp"
|
||||||
android:cacheColorHint="@color/transparent"
|
android:cacheColorHint="@color/transparent"
|
||||||
android:layout_above="@id/remote_composing"
|
android:layout_above="@id/remote_composing"
|
||||||
|
|
114
res/layout/chat_bubble.xml
Normal file
114
res/layout/chat_bubble.xml
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/bubble"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/delete_message"
|
||||||
|
android:button="@drawable/checkbox"
|
||||||
|
android:contentDescription="@string/content_description_delete"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_marginRight="5dp"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/background"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_toLeftOf="@id/delete_message"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/contact_picture"
|
||||||
|
android:src="@drawable/avatar"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/contact_header"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/message"
|
||||||
|
style="@style/font11"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:linksClickable="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="150dp"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
android:layout_centerInParent="true" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/file_transfer_layout"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:paddingRight="5dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="5dp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/file_transfer_action"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/progress_bar"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/status"
|
||||||
|
android:contentDescription="@string/content_description_message_status"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:layout_gravity="top|right"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:adjustViewBounds="true" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/inprogress"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:paddingRight="5dp"
|
||||||
|
android:layout_gravity="top|right"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
|
@ -1,114 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/bubble"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="left"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/delete_message"
|
|
||||||
android:button="@drawable/checkbox"
|
|
||||||
android:contentDescription="@string/content_description_delete"
|
|
||||||
android:layout_marginLeft="5dp"
|
|
||||||
android:layout_marginRight="5dp"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/message_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_toLeftOf="@id/delete_message">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:background="@drawable/resizable_chat_bubble_incoming"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/avatar_layout"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/contact_picture"
|
|
||||||
android:src="@drawable/avatar"
|
|
||||||
android:contentDescription="@string/content_description_contact_picture"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/mask"
|
|
||||||
android:src="@drawable/avatar_chat_mask"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingLeft="10dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/contact_header"
|
|
||||||
style="@style/font9"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/message"
|
|
||||||
style="@style/font11"
|
|
||||||
android:linksClickable="true"
|
|
||||||
android:autoLink="web"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/image"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="150dp"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:maxWidth="250dp"
|
|
||||||
android:maxHeight="250dp"/>
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/file_transfer_layout"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progress_bar"
|
|
||||||
style="@android:style/Widget.ProgressBar.Horizontal"
|
|
||||||
android:paddingRight="5dp"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="5dp"/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/accept_download"
|
|
||||||
android:text="@string/accept"
|
|
||||||
android:background="@drawable/resizable_assistant_button"
|
|
||||||
style="@style/font8"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/progress_bar"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
|
@ -1,112 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/bubble"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/delete_message"
|
|
||||||
android:button="@drawable/checkbox"
|
|
||||||
android:contentDescription="@string/content_description_delete"
|
|
||||||
android:layout_marginLeft="5dp"
|
|
||||||
android:layout_marginRight="5dp"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:background="@drawable/resizable_chat_bubble_outgoing"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_toLeftOf="@id/delete_message"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/contact_picture"
|
|
||||||
android:src="@drawable/avatar"
|
|
||||||
android:paddingLeft="10dp"
|
|
||||||
android:paddingTop="10dp"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="10dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/contact_header"
|
|
||||||
style="@style/font3"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/message"
|
|
||||||
style="@style/font11"
|
|
||||||
android:autoLink="web"
|
|
||||||
android:linksClickable="true"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/image"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="150dp"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
android:layout_centerInParent="true" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/file_transfer_layout"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progress_bar"
|
|
||||||
style="@android:style/Widget.ProgressBar.Horizontal"
|
|
||||||
android:paddingRight="5dp"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="5dp"/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/cancel_upload"
|
|
||||||
android:text="@string/cancel"
|
|
||||||
android:background="@drawable/resizable_confirm_delete_button"
|
|
||||||
style="@style/font15"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/progress_bar"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/status"
|
|
||||||
android:contentDescription="@string/content_description_message_status"
|
|
||||||
android:visibility="invisible"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:layout_gravity="top|right"
|
|
||||||
android:layout_width="20dp"
|
|
||||||
android:layout_height="20dp"
|
|
||||||
android:adjustViewBounds="true" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/inprogress"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:paddingRight="5dp"
|
|
||||||
android:layout_gravity="top|right"
|
|
||||||
android:layout_width="20dp"
|
|
||||||
android:layout_height="20dp"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
|
@ -136,6 +136,7 @@
|
||||||
android:inputType="textPersonName|textCapWords"/>
|
android:inputType="textPersonName|textCapWords"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/contactOrganizationTitle"
|
||||||
android:text="@string/contact_organization"
|
android:text="@string/contact_organization"
|
||||||
style="@style/font13"
|
style="@style/font13"
|
||||||
android:textAllCaps="true"
|
android:textAllCaps="true"
|
||||||
|
|
|
@ -71,6 +71,8 @@
|
||||||
<bool name="allow_only_one_phone_number">false</bool>
|
<bool name="allow_only_one_phone_number">false</bool>
|
||||||
<bool name="allow_only_one_sip_address">false</bool>
|
<bool name="allow_only_one_sip_address">false</bool>
|
||||||
|
|
||||||
|
<bool name="display_contact_organization">true</bool>
|
||||||
|
|
||||||
<bool name="setup_cancel_move_to_back">false</bool>
|
<bool name="setup_cancel_move_to_back">false</bool>
|
||||||
|
|
||||||
<bool name="enable_call_notification">true</bool>
|
<bool name="enable_call_notification">true</bool>
|
||||||
|
|
|
@ -107,6 +107,7 @@
|
||||||
<string name="pref_background_mode_key">pref_background_mode_key</string>
|
<string name="pref_background_mode_key">pref_background_mode_key</string>
|
||||||
<string name="pref_codec_bitrate_limit_key">pref_codec_bitrate_limit_key</string>
|
<string name="pref_codec_bitrate_limit_key">pref_codec_bitrate_limit_key</string>
|
||||||
<string name="pref_adaptive_rate_control_key">pref_adaptive_rate_control_key</string>
|
<string name="pref_adaptive_rate_control_key">pref_adaptive_rate_control_key</string>
|
||||||
|
<string name="pref_echo_tester_key">pref_echo_tester_key</string>
|
||||||
|
|
||||||
<string name="push_reg_id_key">push_reg_id_key</string>
|
<string name="push_reg_id_key">push_reg_id_key</string>
|
||||||
<string name="push_sender_id_key">push_sender_id_key</string>
|
<string name="push_sender_id_key">push_sender_id_key</string>
|
||||||
|
@ -204,4 +205,5 @@
|
||||||
<string name="pref_use_lime_encryption_key">pref_use_lime_encryption_key</string>
|
<string name="pref_use_lime_encryption_key">pref_use_lime_encryption_key</string>
|
||||||
<string name="pref_device_ringtone_key">pref_device_ringtone_key</string>
|
<string name="pref_device_ringtone_key">pref_device_ringtone_key</string>
|
||||||
<string name="pref_auto_answer_key">pref_auto_answer_key</string>
|
<string name="pref_auto_answer_key">pref_auto_answer_key</string>
|
||||||
|
<string name="pref_android_app_settings_key">pref_android_app_settings_key</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -273,6 +273,7 @@
|
||||||
<string name="pref_echo_cancellation">Echo cancellation</string>
|
<string name="pref_echo_cancellation">Echo cancellation</string>
|
||||||
<string name="pref_echo_cancellation_summary">Removes the echo heard by other end</string>
|
<string name="pref_echo_cancellation_summary">Removes the echo heard by other end</string>
|
||||||
<string name="pref_echo_canceller_calibration">Echo canceler calibration</string>
|
<string name="pref_echo_canceller_calibration">Echo canceler calibration</string>
|
||||||
|
<string name="pref_echo_tester">Test echo</string>
|
||||||
<string name="ec_calibrating">Calibrating…</string>
|
<string name="ec_calibrating">Calibrating…</string>
|
||||||
<string name="ec_calibrated">Calibrated in %s ms</string>
|
<string name="ec_calibrated">Calibrated in %s ms</string>
|
||||||
<string name="no_echo">No echo</string>
|
<string name="no_echo">No echo</string>
|
||||||
|
@ -340,6 +341,7 @@
|
||||||
<string name="pref_autostart">Start at boot time</string>
|
<string name="pref_autostart">Start at boot time</string>
|
||||||
<string name="pref_incoming_call_timeout_title">Incoming call hangup (in seconds)</string>
|
<string name="pref_incoming_call_timeout_title">Incoming call hangup (in seconds)</string>
|
||||||
<string name="pref_remote_provisioning_title">Remote provisioning</string>
|
<string name="pref_remote_provisioning_title">Remote provisioning</string>
|
||||||
|
<string name="pref_android_app_settings_title">Android app settings</string>
|
||||||
<string name="pref_primary_account_title">Primary account</string>
|
<string name="pref_primary_account_title">Primary account</string>
|
||||||
<string name="pref_display_name_title">Display name</string>
|
<string name="pref_display_name_title">Display name</string>
|
||||||
<string name="pref_user_name_title">Username</string>
|
<string name="pref_user_name_title">Username</string>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<ContactsSource
|
<ContactsSource
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<!-- Change package ! -->
|
<!-- Change package, leave vnd.android.cursor.item/ before and .profile at the end. -->
|
||||||
<ContactsDataKind
|
<ContactsDataKind
|
||||||
android:mimeType="vnd.android.cursor.item/org.linphone.profile"
|
android:mimeType="vnd.android.cursor.item/org.linphone.profile"
|
||||||
android:icon="@drawable/linphone_logo"
|
android:icon="@drawable/linphone_logo"
|
||||||
|
|
|
@ -70,6 +70,11 @@
|
||||||
android:key="@string/pref_echo_canceller_calibration_key"
|
android:key="@string/pref_echo_canceller_calibration_key"
|
||||||
android:persistent="false"/>
|
android:persistent="false"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:title="@string/pref_echo_tester"
|
||||||
|
android:key="@string/pref_echo_tester_key"
|
||||||
|
android:persistent="false"/>
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:title="@string/pref_adaptive_rate_control"
|
android:title="@string/pref_adaptive_rate_control"
|
||||||
android:key="@string/pref_adaptive_rate_control_key"
|
android:key="@string/pref_adaptive_rate_control_key"
|
||||||
|
@ -346,6 +351,11 @@
|
||||||
android:inputType="textUri"
|
android:inputType="textUri"
|
||||||
android:persistent="false"/>
|
android:persistent="false"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:title="@string/pref_android_app_settings_title"
|
||||||
|
android:key="@string/pref_android_app_settings_key"
|
||||||
|
android:persistent="false"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
|
|
@ -69,11 +69,11 @@ public class AboutFragment extends Fragment implements OnClickListener {
|
||||||
|
|
||||||
sendLogButton = view.findViewById(R.id.send_log);
|
sendLogButton = view.findViewById(R.id.send_log);
|
||||||
sendLogButton.setOnClickListener(this);
|
sendLogButton.setOnClickListener(this);
|
||||||
sendLogButton.setVisibility(org.linphone.LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
|
sendLogButton.setVisibility(LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
resetLogButton = view.findViewById(R.id.reset_log);
|
resetLogButton = view.findViewById(R.id.reset_log);
|
||||||
resetLogButton.setOnClickListener(this);
|
resetLogButton.setOnClickListener(this);
|
||||||
resetLogButton.setVisibility(org.linphone.LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
|
resetLogButton.setVisibility(LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
mListener = new LinphoneCoreListenerBase() {
|
mListener = new LinphoneCoreListenerBase() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -145,7 +145,7 @@ public class AboutFragment extends Fragment implements OnClickListener {
|
||||||
lc.addListener(mListener);
|
lc.addListener(mListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (org.linphone.LinphoneActivity.isInstanciated()) {
|
if (LinphoneActivity.isInstanciated()) {
|
||||||
LinphoneActivity.instance().selectMenu(FragmentsAvailable.ABOUT);
|
LinphoneActivity.instance().selectMenu(FragmentsAvailable.ABOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,8 +154,8 @@ public class AboutFragment extends Fragment implements OnClickListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (org.linphone.LinphoneActivity.isInstanciated()) {
|
if (LinphoneActivity.isInstanciated()) {
|
||||||
LinphoneCore lc = org.linphone.LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
||||||
if (v == sendLogButton) {
|
if (v == sendLogButton) {
|
||||||
if (lc != null) {
|
if (lc != null) {
|
||||||
lc.uploadLogCollection();
|
lc.uploadLogCollection();
|
||||||
|
@ -174,6 +174,4 @@ public class AboutFragment extends Fragment implements OnClickListener {
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,7 @@ public class AccountPreferencesFragment extends PreferencesListFragment {
|
||||||
mPrefs = LinphonePreferences.instance();
|
mPrefs = LinphonePreferences.instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
{
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
PreferenceScreen screen = getPreferenceScreen();
|
PreferenceScreen screen = getPreferenceScreen();
|
||||||
|
@ -69,7 +68,7 @@ public class AccountPreferencesFragment extends PreferencesListFragment {
|
||||||
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isEditTextEmpty(String s){
|
public static boolean isEditTextEmpty(String s) {
|
||||||
return s.equals(""); // really empty.
|
return s.equals(""); // really empty.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.linphone.compatibility.Compatibility;
|
|
||||||
import org.linphone.mediastream.Log;
|
import org.linphone.mediastream.Log;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
@ -68,31 +67,31 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
public BluetoothManager() {
|
public BluetoothManager() {
|
||||||
isBluetoothConnected = false;
|
isBluetoothConnected = false;
|
||||||
if (!ensureInit()) {
|
if (!ensureInit()) {
|
||||||
Log.w("BluetoothManager tried to init but LinphoneService not ready yet...");
|
Log.w("[Bluetooth] Manager tried to init but LinphoneService not ready yet...");
|
||||||
}
|
}
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initBluetooth() {
|
public void initBluetooth() {
|
||||||
if (!ensureInit()) {
|
if (!ensureInit()) {
|
||||||
Log.w("BluetoothManager tried to init bluetooth but LinphoneService not ready yet...");
|
Log.w("[Bluetooth] Manager tried to init bluetooth but LinphoneService not ready yet...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY + "." + BluetoothAssignedNumbers.PLANTRONICS);
|
filter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY + "." + BluetoothAssignedNumbers.PLANTRONICS);
|
||||||
filter.addAction(Compatibility.getAudioManagerEventForBluetoothConnectionStateChangedEvent());
|
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
|
||||||
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
|
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
|
||||||
filter.addAction(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
|
filter.addAction(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
|
||||||
mContext.registerReceiver(this, filter);
|
mContext.registerReceiver(this, filter);
|
||||||
Log.d("Bluetooth receiver started");
|
Log.d("[Bluetooth] Receiver started");
|
||||||
|
|
||||||
startBluetooth();
|
startBluetooth();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startBluetooth() {
|
private void startBluetooth() {
|
||||||
if (isBluetoothConnected) {
|
if (isBluetoothConnected) {
|
||||||
Log.e("Bluetooth already started");
|
Log.e("[Bluetooth] Already started, skipping...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,14 +99,14 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
|
|
||||||
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
|
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
|
||||||
if (mProfileListener != null) {
|
if (mProfileListener != null) {
|
||||||
Log.w("Bluetooth headset profile was already opened, let's close it");
|
Log.w("[Bluetooth] Headset profile was already opened, let's close it");
|
||||||
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
||||||
}
|
}
|
||||||
|
|
||||||
mProfileListener = new BluetoothProfile.ServiceListener() {
|
mProfileListener = new BluetoothProfile.ServiceListener() {
|
||||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||||
if (profile == BluetoothProfile.HEADSET) {
|
if (profile == BluetoothProfile.HEADSET) {
|
||||||
Log.d("Bluetooth headset connected");
|
Log.d("[Bluetooth] Headset connected");
|
||||||
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
||||||
isBluetoothConnected = true;
|
isBluetoothConnected = true;
|
||||||
}
|
}
|
||||||
|
@ -116,17 +115,17 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
if (profile == BluetoothProfile.HEADSET) {
|
if (profile == BluetoothProfile.HEADSET) {
|
||||||
mBluetoothHeadset = null;
|
mBluetoothHeadset = null;
|
||||||
isBluetoothConnected = false;
|
isBluetoothConnected = false;
|
||||||
Log.d("Bluetooth headset disconnected");
|
Log.d("[Bluetooth] Headset disconnected");
|
||||||
LinphoneManager.getInstance().routeAudioToReceiver();
|
LinphoneManager.getInstance().routeAudioToReceiver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
boolean success = mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
|
boolean success = mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Log.e("Bluetooth getProfileProxy failed !");
|
Log.e("[Bluetooth] getProfileProxy failed !");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.w("Bluetooth interface disabled on device");
|
Log.w("[Bluetooth] Interface disabled on device");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +152,7 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() && mAudioManager != null && mAudioManager.isBluetoothScoAvailableOffCall()) {
|
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() && mAudioManager != null && mAudioManager.isBluetoothScoAvailableOffCall()) {
|
||||||
if (isBluetoothHeadsetAvailable()) {
|
if (isBluetoothHeadsetAvailable()) {
|
||||||
if (mAudioManager != null && !mAudioManager.isBluetoothScoOn()) {
|
if (mAudioManager != null && !mAudioManager.isBluetoothScoOn()) {
|
||||||
Log.d("Bluetooth sco off, let's start it");
|
Log.d("[Bluetooth] SCO off, let's start it");
|
||||||
mAudioManager.setBluetoothScoOn(true);
|
mAudioManager.setBluetoothScoOn(true);
|
||||||
mAudioManager.startBluetoothSco();
|
mAudioManager.startBluetoothSco();
|
||||||
}
|
}
|
||||||
|
@ -180,12 +179,12 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (ok) {
|
||||||
if (retries > 0) {
|
if (retries > 0) {
|
||||||
Log.d("Bluetooth route ok after " + retries + " retries");
|
Log.d("[Bluetooth] Audio route ok after " + retries + " retries");
|
||||||
} else {
|
} else {
|
||||||
Log.d("Bluetooth route ok");
|
Log.d("[Bluetooth] Audio route ok");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d("Bluetooth still not ok...");
|
Log.d("[Bluetooth] Audio route still not ok...");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -212,7 +211,7 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d(isHeadsetConnected ? "Headset found, bluetooth audio route available" : "No headset found, bluetooth audio route unavailable");
|
Log.d(isHeadsetConnected ? "[Bluetooth] Headset found, bluetooth audio route available" : "[Bluetooth] No headset found, bluetooth audio route unavailable");
|
||||||
}
|
}
|
||||||
return isHeadsetConnected;
|
return isHeadsetConnected;
|
||||||
}
|
}
|
||||||
|
@ -237,12 +236,12 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
mAudioManager.stopBluetoothSco();
|
mAudioManager.stopBluetoothSco();
|
||||||
mAudioManager.setBluetoothScoOn(false);
|
mAudioManager.setBluetoothScoOn(false);
|
||||||
}
|
}
|
||||||
Log.w("Bluetooth sco disconnected!");
|
Log.w("[Bluetooth] SCO disconnected!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopBluetooth() {
|
public void stopBluetooth() {
|
||||||
Log.w("Stopping bluetooth...");
|
Log.w("[Bluetooth] Stopping...");
|
||||||
isBluetoothConnected = false;
|
isBluetoothConnected = false;
|
||||||
|
|
||||||
disableBluetoothSCO();
|
disableBluetoothSCO();
|
||||||
|
@ -253,7 +252,7 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
}
|
}
|
||||||
mBluetoothDevice = null;
|
mBluetoothDevice = null;
|
||||||
|
|
||||||
Log.w("Bluetooth stopped!");
|
Log.w("[Bluetooth] Stopped!");
|
||||||
|
|
||||||
if (LinphoneManager.isInstanciated()) {
|
if (LinphoneManager.isInstanciated()) {
|
||||||
LinphoneManager.getInstance().routeAudioToReceiver();
|
LinphoneManager.getInstance().routeAudioToReceiver();
|
||||||
|
@ -266,7 +265,7 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mContext.unregisterReceiver(this);
|
mContext.unregisterReceiver(this);
|
||||||
Log.d("Bluetooth receiver stopped");
|
Log.d("[Bluetooth] Receiver stopped");
|
||||||
} catch (Exception e) {}
|
} catch (Exception e) {}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
|
@ -278,30 +277,30 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if (Compatibility.getAudioManagerEventForBluetoothConnectionStateChangedEvent().equals(action)) {
|
if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(action)) {
|
||||||
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 0);
|
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 0);
|
||||||
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
||||||
Log.d("Bluetooth sco state => connected");
|
Log.d("[Bluetooth] SCO state: connected");
|
||||||
// LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH);
|
// LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH);
|
||||||
isScoConnected = true;
|
isScoConnected = true;
|
||||||
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
||||||
Log.d("Bluetooth sco state => disconnected");
|
Log.d("[Bluetooth] SCO state: disconnected");
|
||||||
// LinphoneManager.getInstance().audioStateChanged(AudioState.SPEAKER);
|
// LinphoneManager.getInstance().audioStateChanged(AudioState.SPEAKER);
|
||||||
isScoConnected = false;
|
isScoConnected = false;
|
||||||
} else {
|
} else {
|
||||||
Log.d("Bluetooth sco state => " + state);
|
Log.d("[Bluetooth] SCO state: " + state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
|
else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
|
||||||
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.STATE_DISCONNECTED);
|
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.STATE_DISCONNECTED);
|
||||||
if (state == 0) {
|
if (state == 0) {
|
||||||
Log.d("Bluetooth state => disconnected");
|
Log.d("[Bluetooth] State: disconnected");
|
||||||
stopBluetooth();
|
stopBluetooth();
|
||||||
} else if (state == 2) {
|
} else if (state == 2) {
|
||||||
Log.d("Bluetooth state => connected");
|
Log.d("[Bluetooth] State: connected");
|
||||||
startBluetooth();
|
startBluetooth();
|
||||||
} else {
|
} else {
|
||||||
Log.d("Bluetooth state => " + state);
|
Log.d("[Bluetooth] State: " + state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (intent.getAction().equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) {
|
else if (intent.getAction().equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) {
|
||||||
|
@ -314,7 +313,7 @@ public class BluetoothManager extends BroadcastReceiver {
|
||||||
if (eventName.equals("BUTTON") && args.length >= 3) {
|
if (eventName.equals("BUTTON") && args.length >= 3) {
|
||||||
Integer buttonID = (Integer) args[1];
|
Integer buttonID = (Integer) args[1];
|
||||||
Integer mode = (Integer) args[2];
|
Integer mode = (Integer) args[2];
|
||||||
Log.d("Bluetooth event: " + command + " : " + eventName + ", id = " + buttonID + " (" + mode + ")");
|
Log.d("[Bluetooth] Event: " + command + " : " + eventName + ", id = " + buttonID + " (" + mode + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
||||||
private boolean isConferenceRunning = false;
|
private boolean isConferenceRunning = false;
|
||||||
private LinphoneCoreListenerBase mListener;
|
private LinphoneCoreListenerBase mListener;
|
||||||
private DrawerLayout sideMenu;
|
private DrawerLayout sideMenu;
|
||||||
|
private boolean mProximitySensingEnabled;
|
||||||
|
|
||||||
public static CallActivity instance() {
|
public static CallActivity instance() {
|
||||||
return instance;
|
return instance;
|
||||||
|
@ -800,8 +801,22 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showAudioView() {
|
private void enableProximitySensing(boolean enable){
|
||||||
|
if (enable){
|
||||||
|
if (!mProximitySensingEnabled){
|
||||||
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
||||||
|
mProximitySensingEnabled = true;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if (mProximitySensingEnabled){
|
||||||
|
mSensorManager.unregisterListener(this);
|
||||||
|
mProximitySensingEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showAudioView() {
|
||||||
|
enableProximitySensing(true);
|
||||||
replaceFragmentVideoByAudio();
|
replaceFragmentVideoByAudio();
|
||||||
displayAudioCall();
|
displayAudioCall();
|
||||||
showStatusBar();
|
showStatusBar();
|
||||||
|
@ -816,7 +831,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
||||||
}
|
}
|
||||||
refreshInCallActions();
|
refreshInCallActions();
|
||||||
|
|
||||||
mSensorManager.unregisterListener(this);
|
enableProximitySensing(false);
|
||||||
replaceFragmentAudioByVideo();
|
replaceFragmentAudioByVideo();
|
||||||
hideStatusBar();
|
hideStatusBar();
|
||||||
}
|
}
|
||||||
|
@ -1173,7 +1188,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
||||||
handleViewIntent();
|
handleViewIntent();
|
||||||
|
|
||||||
if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
|
if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
|
||||||
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
enableProximitySensing(true);
|
||||||
removeCallbacks();
|
removeCallbacks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1223,10 +1238,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
||||||
mControlsHandler.removeCallbacks(mControls);
|
mControlsHandler.removeCallbacks(mControls);
|
||||||
}
|
}
|
||||||
mControls = null;
|
mControls = null;
|
||||||
|
enableProximitySensing(false);
|
||||||
if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
|
|
||||||
mSensorManager.unregisterListener(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1239,7 +1251,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
||||||
mControls = null;
|
mControls = null;
|
||||||
mControlsHandler = null;
|
mControlsHandler = null;
|
||||||
|
|
||||||
mSensorManager.unregisterListener(this);
|
enableProximitySensing(false);
|
||||||
|
|
||||||
unbindDrawables(findViewById(R.id.topLayout));
|
unbindDrawables(findViewById(R.id.topLayout));
|
||||||
instance = null;
|
instance = null;
|
||||||
|
@ -1510,7 +1522,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
||||||
private void displayConference(boolean isInConf){
|
private void displayConference(boolean isInConf){
|
||||||
if(isInConf) {
|
if(isInConf) {
|
||||||
mControlsLayout.setVisibility(View.VISIBLE);
|
mControlsLayout.setVisibility(View.VISIBLE);
|
||||||
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
enableProximitySensing(true);
|
||||||
mActiveCallHeader.setVisibility(View.GONE);
|
mActiveCallHeader.setVisibility(View.GONE);
|
||||||
mNoCurrentCall.setVisibility(View.GONE);
|
mNoCurrentCall.setVisibility(View.GONE);
|
||||||
conferenceList.removeAllViews();
|
conferenceList.removeAllViews();
|
||||||
|
|
|
@ -21,8 +21,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@ -37,22 +42,29 @@ import org.linphone.core.LinphoneCore;
|
||||||
import org.linphone.core.LinphoneCoreFactory;
|
import org.linphone.core.LinphoneCoreFactory;
|
||||||
import org.linphone.core.LinphoneCoreListenerBase;
|
import org.linphone.core.LinphoneCoreListenerBase;
|
||||||
import org.linphone.mediastream.Log;
|
import org.linphone.mediastream.Log;
|
||||||
import org.linphone.ui.BubbleChat;
|
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.media.ExifInterface;
|
import android.media.ExifInterface;
|
||||||
|
import android.media.ThumbnailUtils;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -61,9 +73,10 @@ import android.os.Parcelable;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -72,7 +85,6 @@ import android.view.ViewGroup;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.AbsListView;
|
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
|
@ -81,6 +93,7 @@ import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
@ -111,6 +124,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
private SearchContactsListAdapter searchAdapter;
|
private SearchContactsListAdapter searchAdapter;
|
||||||
private ListView messagesList, resultContactsSearch;
|
private ListView messagesList, resultContactsSearch;
|
||||||
private LayoutInflater inflater;
|
private LayoutInflater inflater;
|
||||||
|
private Bitmap defaultBitmap;
|
||||||
|
|
||||||
private boolean isEditMode = false;
|
private boolean isEditMode = false;
|
||||||
private LinphoneContact contact;
|
private LinphoneContact contact;
|
||||||
|
@ -143,9 +157,10 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
}
|
}
|
||||||
|
|
||||||
//Initialize UI
|
//Initialize UI
|
||||||
|
defaultBitmap = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.chat_picture_over);
|
||||||
|
|
||||||
contactName = (TextView) view.findViewById(R.id.contact_name);
|
contactName = (TextView) view.findViewById(R.id.contact_name);
|
||||||
messagesList = (ListView) view.findViewById(R.id.chat_message_list);
|
messagesList = (ListView) view.findViewById(R.id.chat_message_list);
|
||||||
messagesList.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
|
|
||||||
searchContactField = (EditText) view.findViewById(R.id.search_contact_field);
|
searchContactField = (EditText) view.findViewById(R.id.search_contact_field);
|
||||||
resultContactsSearch = (ListView) view.findViewById(R.id.result_contacts);
|
resultContactsSearch = (ListView) view.findViewById(R.id.result_contacts);
|
||||||
|
|
||||||
|
@ -214,7 +229,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
LinphoneService.instance().removeMessageNotification();
|
LinphoneService.instance().removeMessageNotification();
|
||||||
cr.markAsRead();
|
cr.markAsRead();
|
||||||
adapter.addMessage(cr.getHistory(1)[0]);
|
adapter.addMessage(cr.getHistory(1)[0]);
|
||||||
messagesList.setSelection(adapter.getCount()-1);
|
|
||||||
|
|
||||||
String externalBodyUrl = message.getExternalBodyUrl();
|
String externalBodyUrl = message.getExternalBodyUrl();
|
||||||
LinphoneContent fileTransferContent = message.getFileTransferInformation();
|
LinphoneContent fileTransferContent = message.getFileTransferInformation();
|
||||||
|
@ -320,135 +334,11 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatMessageAdapter extends BaseAdapter {
|
|
||||||
ArrayList<LinphoneChatMessage> history;
|
|
||||||
Context context;
|
|
||||||
|
|
||||||
public ChatMessageAdapter(Context c) {
|
|
||||||
context = c;
|
|
||||||
history = new ArrayList<LinphoneChatMessage>();
|
|
||||||
refreshHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
if (history != null) {
|
|
||||||
history.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshHistory() {
|
|
||||||
history.clear();
|
|
||||||
LinphoneChatMessage[] messages = chatRoom.getHistory();
|
|
||||||
history.addAll(Arrays.asList(messages));
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMessage(LinphoneChatMessage message) {
|
|
||||||
history.add(message);
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return history.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LinphoneChatMessage getItem(int position) {
|
|
||||||
return history.get(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
return history.get(position).getStorageId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getView(final int position, View convertView, ViewGroup parent) {
|
|
||||||
LinphoneChatMessage message = history.get(position);
|
|
||||||
RelativeLayout rlayout;
|
|
||||||
|
|
||||||
if (convertView != null) {
|
|
||||||
rlayout = (RelativeLayout) convertView;
|
|
||||||
View bbv = rlayout.getChildAt(0);
|
|
||||||
rlayout.removeAllViews();
|
|
||||||
BubbleChat bbc = (BubbleChat) bbv.getTag();
|
|
||||||
bbc.destroy();
|
|
||||||
} else {
|
|
||||||
rlayout = new RelativeLayout(context);
|
|
||||||
}
|
|
||||||
BubbleChat bubble = new BubbleChat(context, message, contact);
|
|
||||||
View v = bubble.getView();
|
|
||||||
v.setTag(bubble);
|
|
||||||
|
|
||||||
registerForContextMenu(v);
|
|
||||||
|
|
||||||
CheckBox deleteChatBubble = (CheckBox) v.findViewById(R.id.delete_message);
|
|
||||||
|
|
||||||
if(isEditMode) {
|
|
||||||
deleteChatBubble.setVisibility(View.VISIBLE);
|
|
||||||
if(message.isOutgoing()){
|
|
||||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
|
|
||||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
|
||||||
layoutParams.setMargins(100, 10, 10, 10);
|
|
||||||
v.setLayoutParams(layoutParams);
|
|
||||||
} else {
|
|
||||||
LinearLayout message_layout = (LinearLayout) v.findViewById(R.id.message_content);
|
|
||||||
message_layout.setGravity(Gravity.RIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteChatBubble.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
|
||||||
messagesList.setItemChecked(position, b);
|
|
||||||
if (getNbItemsChecked() == getCount()) {
|
|
||||||
deselectAll.setVisibility(View.VISIBLE);
|
|
||||||
selectAll.setVisibility(View.GONE);
|
|
||||||
enabledDeleteButton(true);
|
|
||||||
} else {
|
|
||||||
if (getNbItemsChecked() == 0) {
|
|
||||||
deselectAll.setVisibility(View.GONE);
|
|
||||||
selectAll.setVisibility(View.VISIBLE);
|
|
||||||
enabledDeleteButton(false);
|
|
||||||
} else {
|
|
||||||
deselectAll.setVisibility(View.GONE);
|
|
||||||
selectAll.setVisibility(View.VISIBLE);
|
|
||||||
enabledDeleteButton(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(messagesList.isItemChecked(position)) {
|
|
||||||
deleteChatBubble.setChecked(true);
|
|
||||||
} else {
|
|
||||||
deleteChatBubble.setChecked(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
rlayout.addView(v);
|
|
||||||
} else {
|
|
||||||
if(message.isOutgoing()){
|
|
||||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
|
|
||||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
|
||||||
layoutParams.setMargins(100, 10, 10, 10);
|
|
||||||
v.setLayoutParams(layoutParams);
|
|
||||||
} else {
|
|
||||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
|
|
||||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
|
||||||
layoutParams.setMargins(10, 10, 100, 10);
|
|
||||||
v.setLayoutParams(layoutParams);
|
|
||||||
}
|
|
||||||
rlayout.addView(v);
|
|
||||||
}
|
|
||||||
return rlayout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initChatRoom(String sipUri) {
|
public void initChatRoom(String sipUri) {
|
||||||
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
||||||
|
|
||||||
LinphoneAddress lAddress = null;
|
LinphoneAddress lAddress = null;
|
||||||
if(sipUri == null){
|
if (sipUri == null) {
|
||||||
initNewChatConversation();
|
initNewChatConversation();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
@ -477,7 +367,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayMessageList() {
|
private void displayMessageList() {
|
||||||
if(chatRoom != null) {
|
if (chatRoom != null) {
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
adapter.refreshHistory();
|
adapter.refreshHistory();
|
||||||
} else {
|
} else {
|
||||||
|
@ -488,7 +378,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayChatHeader(LinphoneAddress address) {
|
private void displayChatHeader(LinphoneAddress address) {
|
||||||
if(contact != null) {
|
if (contact != null) {
|
||||||
contactName.setText(contact.getFullName());
|
contactName.setText(contact.getFullName());
|
||||||
} else if(address != null){
|
} else if(address != null){
|
||||||
contactName.setText(LinphoneUtils.getAddressDisplayName(address));
|
contactName.setText(LinphoneUtils.getAddressDisplayName(address));
|
||||||
|
@ -580,6 +470,10 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
adapter.destroy();
|
adapter.destroy();
|
||||||
}
|
}
|
||||||
|
if (defaultBitmap != null) {
|
||||||
|
defaultBitmap.recycle();
|
||||||
|
defaultBitmap = null;
|
||||||
|
}
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,7 +512,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
String draft = getArguments().getString("messageDraft");
|
String draft = getArguments().getString("messageDraft");
|
||||||
message.setText(draft);
|
message.setText(draft);
|
||||||
|
|
||||||
if(!newChatConversation) {
|
if (!newChatConversation) {
|
||||||
initChatRoom(sipUri);
|
initChatRoom(sipUri);
|
||||||
searchContactField.setVisibility(View.GONE);
|
searchContactField.setVisibility(View.GONE);
|
||||||
resultContactsSearch.setVisibility(View.GONE);
|
resultContactsSearch.setVisibility(View.GONE);
|
||||||
|
@ -626,10 +520,10 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectAllList(boolean isSelectAll){
|
private void selectAllList(boolean isSelectAll) {
|
||||||
int size = messagesList.getAdapter().getCount();
|
int size = messagesList.getAdapter().getCount();
|
||||||
for(int i=0; i<size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
messagesList.setItemChecked(i,isSelectAll);
|
messagesList.setItemChecked(i, isSelectAll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,8 +536,8 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
|
|
||||||
private void removeChats(){
|
private void removeChats(){
|
||||||
int size = messagesList.getAdapter().getCount();
|
int size = messagesList.getAdapter().getCount();
|
||||||
for(int i=0; i<size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
if(messagesList.isItemChecked(i)){
|
if (messagesList.isItemChecked(i)) {
|
||||||
LinphoneChatMessage message = (LinphoneChatMessage) messagesList.getAdapter().getItem(i);
|
LinphoneChatMessage message = (LinphoneChatMessage) messagesList.getAdapter().getItem(i);
|
||||||
chatRoom.deleteMessage(message);
|
chatRoom.deleteMessage(message);
|
||||||
}
|
}
|
||||||
|
@ -827,7 +721,9 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
txt = message.getText();
|
txt = message.getText();
|
||||||
}
|
}
|
||||||
if (txt != null) {
|
if (txt != null) {
|
||||||
Compatibility.copyTextToClipboard(getActivity(), txt);
|
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
|
ClipData clip = android.content.ClipData.newPlainText("Message", txt);
|
||||||
|
clipboard.setPrimaryClip(clip);
|
||||||
LinphoneActivity.instance().displayCustomToast(getString(R.string.text_copied_to_clipboard), Toast.LENGTH_SHORT);
|
LinphoneActivity.instance().displayCustomToast(getString(R.string.text_copied_to_clipboard), Toast.LENGTH_SHORT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1038,7 +934,492 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
searchAdapter.notifyDataSetChanged();
|
searchAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ChatMessageAdapter extends BaseAdapter {
|
||||||
|
private class ViewHolder implements LinphoneChatMessage.LinphoneChatMessageListener {
|
||||||
|
public int id;
|
||||||
|
public RelativeLayout bubbleLayout;
|
||||||
|
public CheckBox delete;
|
||||||
|
public LinearLayout background;
|
||||||
|
public ImageView contactPicture;
|
||||||
|
public TextView contactName;
|
||||||
|
public TextView messageText;
|
||||||
|
public ImageView messageImage;
|
||||||
|
public RelativeLayout fileTransferLayout;
|
||||||
|
public ProgressBar fileTransferProgressBar;
|
||||||
|
public Button fileTransferAction;
|
||||||
|
public ImageView messageStatus;
|
||||||
|
public ProgressBar messageSendingInProgress;
|
||||||
|
|
||||||
|
public ViewHolder(View view) {
|
||||||
|
id = view.getId();
|
||||||
|
bubbleLayout = (RelativeLayout) view.findViewById(R.id.bubble);
|
||||||
|
delete = (CheckBox) view.findViewById(R.id.delete_message);
|
||||||
|
background = (LinearLayout) view.findViewById(R.id.background);
|
||||||
|
contactPicture = (ImageView) view.findViewById(R.id.contact_picture);
|
||||||
|
contactName = (TextView) view.findViewById(R.id.contact_header);
|
||||||
|
messageText = (TextView) view.findViewById(R.id.message);
|
||||||
|
messageImage = (ImageView) view.findViewById(R.id.image);
|
||||||
|
fileTransferLayout = (RelativeLayout) view.findViewById(R.id.file_transfer_layout);
|
||||||
|
fileTransferProgressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
|
||||||
|
fileTransferAction = (Button) view.findViewById(R.id.file_transfer_action);
|
||||||
|
messageStatus = (ImageView) view.findViewById(R.id.status);
|
||||||
|
messageSendingInProgress = (ProgressBar) view.findViewById(R.id.inprogress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinphoneChatMessageFileTransferSent(LinphoneChatMessage msg, LinphoneContent content, int offset, int size, LinphoneBuffer bufferToFill) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinphoneChatMessageFileTransferProgressChanged(LinphoneChatMessage msg, LinphoneContent content, int offset, int total) {
|
||||||
|
if (msg.getStorageId() == id) fileTransferProgressBar.setProgress(offset * 100 / total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<LinphoneChatMessage> history;
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
public ChatMessageAdapter(Context c) {
|
||||||
|
context = c;
|
||||||
|
history = new ArrayList<LinphoneChatMessage>();
|
||||||
|
refreshHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
if (history != null) {
|
||||||
|
history.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshHistory() {
|
||||||
|
history.clear();
|
||||||
|
LinphoneChatMessage[] messages = chatRoom.getHistory();
|
||||||
|
history.addAll(Arrays.asList(messages));
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessage(LinphoneChatMessage message) {
|
||||||
|
history.add(message);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
messagesList.setSelection(getCount() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return history.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LinphoneChatMessage getItem(int position) {
|
||||||
|
return history.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return history.get(position).getStorageId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(final int position, View convertView, ViewGroup parent) {
|
||||||
|
final LinphoneChatMessage message = history.get(position);
|
||||||
|
View view = null;
|
||||||
|
final ViewHolder holder;
|
||||||
|
boolean sameMessage = false;
|
||||||
|
|
||||||
|
if (convertView != null) {
|
||||||
|
view = convertView;
|
||||||
|
holder = (ViewHolder) view.getTag();
|
||||||
|
LinphoneManager.removeListener(holder);
|
||||||
|
} else {
|
||||||
|
view = LayoutInflater.from(context).inflate(R.layout.chat_bubble, null);
|
||||||
|
holder = new ViewHolder(view);
|
||||||
|
view.setTag(holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (holder.id == message.getStorageId()) {
|
||||||
|
sameMessage = true;
|
||||||
|
} else {
|
||||||
|
holder.id = message.getStorageId();
|
||||||
|
}
|
||||||
|
view.setId(holder.id);
|
||||||
|
registerForContextMenu(view);
|
||||||
|
|
||||||
|
LinphoneChatMessage.State status = message.getStatus();
|
||||||
|
String externalBodyUrl = message.getExternalBodyUrl();
|
||||||
|
LinphoneContent fileTransferContent = message.getFileTransferInformation();
|
||||||
|
|
||||||
|
holder.delete.setVisibility(View.GONE);
|
||||||
|
holder.messageText.setVisibility(View.GONE);
|
||||||
|
holder.messageImage.setVisibility(View.GONE);
|
||||||
|
holder.fileTransferLayout.setVisibility(View.GONE);
|
||||||
|
holder.fileTransferProgressBar.setProgress(0);
|
||||||
|
holder.fileTransferAction.setEnabled(true);
|
||||||
|
holder.messageStatus.setVisibility(View.INVISIBLE);
|
||||||
|
holder.messageSendingInProgress.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
String displayName = message.getFrom().getDisplayName();
|
||||||
|
if (displayName == null) {
|
||||||
|
displayName = message.getFrom().getUserName();
|
||||||
|
}
|
||||||
|
if (!message.isOutgoing()) {
|
||||||
|
if (contact != null) {
|
||||||
|
if (contact != null && contact.getFullName() != null) {
|
||||||
|
displayName = contact.getFullName();
|
||||||
|
}
|
||||||
|
if (contact.hasPhoto()) {
|
||||||
|
Bitmap photo = contact.getPhoto();
|
||||||
|
if (photo != null) {
|
||||||
|
holder.contactPicture.setImageBitmap(photo);
|
||||||
|
} else {
|
||||||
|
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.contactPicture.setImageResource(R.drawable.avatar);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.contactPicture.setImageResource(R.drawable.avatar);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.contactPicture.setImageResource(R.drawable.avatar);
|
||||||
|
}
|
||||||
|
holder.contactName.setText(timestampToHumanDate(context, message.getTime()) + " - " + displayName);
|
||||||
|
|
||||||
|
if (status == LinphoneChatMessage.State.NotDelivered) {
|
||||||
|
holder.messageStatus.setVisibility(View.VISIBLE);
|
||||||
|
holder.messageStatus.setImageResource(R.drawable.chat_message_not_delivered);
|
||||||
|
} else if (status == LinphoneChatMessage.State.InProgress) {
|
||||||
|
holder.messageSendingInProgress.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (externalBodyUrl != null || fileTransferContent != null) {
|
||||||
|
String appData = message.getAppData();
|
||||||
|
|
||||||
|
if (message.isOutgoing() && appData != null) {
|
||||||
|
holder.messageImage.setVisibility(View.VISIBLE);
|
||||||
|
if (!sameMessage) loadBitmap(appData, holder.messageImage);
|
||||||
|
|
||||||
|
if (LinphoneManager.getInstance().getMessageUploadPending() != null && LinphoneManager.getInstance().getMessageUploadPending().getStorageId() == message.getStorageId()) {
|
||||||
|
holder.messageSendingInProgress.setVisibility(View.GONE);
|
||||||
|
holder.fileTransferLayout.setVisibility(View.VISIBLE);
|
||||||
|
LinphoneManager.addListener(holder);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (appData != null && !LinphoneManager.getInstance().isMessagePending(message) && appData.contains(context.getString(R.string.temp_photo_name_with_date).split("%s")[0])) {
|
||||||
|
appData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appData == null) {
|
||||||
|
LinphoneManager.addListener(holder);
|
||||||
|
holder.fileTransferLayout.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
if (LinphoneManager.getInstance().isMessagePending(message)) {
|
||||||
|
LinphoneManager.addListener(holder);
|
||||||
|
holder.fileTransferAction.setEnabled(false);
|
||||||
|
holder.fileTransferLayout.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
LinphoneManager.removeListener(holder);
|
||||||
|
holder.fileTransferLayout.setVisibility(View.GONE);
|
||||||
|
holder.messageImage.setVisibility(View.VISIBLE);
|
||||||
|
if (!sameMessage) loadBitmap(appData, holder.messageImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Spanned text = null;
|
||||||
|
String msg = message.getText();
|
||||||
|
if (msg != null) {
|
||||||
|
text = getTextWithHttpLinks(msg);
|
||||||
|
holder.messageText.setText(text);
|
||||||
|
holder.messageText.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
holder.messageText.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.isOutgoing()) {
|
||||||
|
holder.fileTransferAction.setText(getString(R.string.cancel));
|
||||||
|
holder.fileTransferAction.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (LinphoneManager.getInstance().getMessageUploadPending() != null) {
|
||||||
|
holder.fileTransferProgressBar.setVisibility(View.GONE);
|
||||||
|
holder.fileTransferProgressBar.setProgress(0);
|
||||||
|
message.cancelFileTransfer();
|
||||||
|
LinphoneManager.getInstance().setUploadPendingFileMessage(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
holder.fileTransferAction.setText(getString(R.string.accept));
|
||||||
|
holder.fileTransferAction.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (context.getPackageManager().checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, context.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
v.setEnabled(false);
|
||||||
|
String extension = message.getFileTransferInformation().getSubtype();
|
||||||
|
String filename = context.getString(R.string.temp_photo_name_with_date).replace("%s", String.valueOf(System.currentTimeMillis())) + "." + extension;
|
||||||
|
File file = new File(Environment.getExternalStorageDirectory(), filename);
|
||||||
|
message.setAppData(filename);
|
||||||
|
LinphoneManager.getInstance().addDownloadMessagePending(message);
|
||||||
|
message.setListener(LinphoneManager.getInstance());
|
||||||
|
message.setFileTransferFilepath(file.getPath());
|
||||||
|
message.downloadFile();
|
||||||
|
} else {
|
||||||
|
Log.w("WRITE_EXTERNAL_STORAGE permission not granted, won't be able to store the downloaded file");
|
||||||
|
LinphoneActivity.instance().checkAndRequestExternalStoragePermission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||||
|
if (message.isOutgoing()) {
|
||||||
|
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||||
|
layoutParams.setMargins(100, 10, 10, 10);
|
||||||
|
holder.background.setBackgroundResource(R.drawable.resizable_chat_bubble_outgoing);
|
||||||
|
holder.contactName.setTextAppearance(R.style.font3);
|
||||||
|
holder.fileTransferAction.setTextAppearance(R.style.font15);
|
||||||
|
holder.fileTransferAction.setBackgroundResource(R.drawable.resizable_confirm_delete_button);
|
||||||
|
} else {
|
||||||
|
if (isEditMode) {
|
||||||
|
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||||
|
layoutParams.setMargins(100, 10, 10, 10);
|
||||||
|
} else {
|
||||||
|
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||||
|
layoutParams.setMargins(10, 10, 100, 10);
|
||||||
|
}
|
||||||
|
holder.background.setBackgroundResource(R.drawable.resizable_chat_bubble_incoming);
|
||||||
|
holder.contactName.setTextAppearance(R.style.font9);
|
||||||
|
holder.fileTransferAction.setTextAppearance(R.style.font8);
|
||||||
|
holder.fileTransferAction.setBackgroundResource(R.drawable.resizable_assistant_button);
|
||||||
|
}
|
||||||
|
holder.bubbleLayout.setLayoutParams(layoutParams);
|
||||||
|
|
||||||
|
if (isEditMode) {
|
||||||
|
holder.delete.setVisibility(View.VISIBLE);
|
||||||
|
holder.delete.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||||
|
messagesList.setItemChecked(position, b);
|
||||||
|
if (getNbItemsChecked() == getCount()) {
|
||||||
|
deselectAll.setVisibility(View.VISIBLE);
|
||||||
|
selectAll.setVisibility(View.GONE);
|
||||||
|
enabledDeleteButton(true);
|
||||||
|
} else {
|
||||||
|
if (getNbItemsChecked() == 0) {
|
||||||
|
deselectAll.setVisibility(View.GONE);
|
||||||
|
selectAll.setVisibility(View.VISIBLE);
|
||||||
|
enabledDeleteButton(false);
|
||||||
|
} else {
|
||||||
|
deselectAll.setVisibility(View.GONE);
|
||||||
|
selectAll.setVisibility(View.VISIBLE);
|
||||||
|
enabledDeleteButton(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (messagesList.isItemChecked(position)) {
|
||||||
|
holder.delete.setChecked(true);
|
||||||
|
} else {
|
||||||
|
holder.delete.setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String timestampToHumanDate(Context context, long timestamp) {
|
||||||
|
try {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.setTimeInMillis(timestamp);
|
||||||
|
|
||||||
|
SimpleDateFormat dateFormat;
|
||||||
|
if (isToday(cal)) {
|
||||||
|
dateFormat = new SimpleDateFormat(context.getResources().getString(R.string.today_date_format));
|
||||||
|
} else {
|
||||||
|
dateFormat = new SimpleDateFormat(context.getResources().getString(R.string.messages_date_format));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateFormat.format(cal.getTime());
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
return String.valueOf(timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isToday(Calendar cal) {
|
||||||
|
return isSameDay(cal, Calendar.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSameDay(Calendar cal1, Calendar cal2) {
|
||||||
|
if (cal1 == null || cal2 == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
|
||||||
|
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
|
||||||
|
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Spanned getTextWithHttpLinks(String text) {
|
||||||
|
if (text.contains("<")) {
|
||||||
|
text = text.replace("<", "<");
|
||||||
|
}
|
||||||
|
if (text.contains(">")) {
|
||||||
|
text = text.replace(">", ">");
|
||||||
|
}
|
||||||
|
if (text.contains("http://")) {
|
||||||
|
int indexHttp = text.indexOf("http://");
|
||||||
|
int indexFinHttp = text.indexOf(" ", indexHttp) == -1 ? text.length() : text.indexOf(" ", indexHttp);
|
||||||
|
String link = text.substring(indexHttp, indexFinHttp);
|
||||||
|
String linkWithoutScheme = link.replace("http://", "");
|
||||||
|
text = text.replaceFirst(link, "<a href=\"" + link + "\">" + linkWithoutScheme + "</a>");
|
||||||
|
}
|
||||||
|
if (text.contains("https://")) {
|
||||||
|
int indexHttp = text.indexOf("https://");
|
||||||
|
int indexFinHttp = text.indexOf(" ", indexHttp) == -1 ? text.length() : text.indexOf(" ", indexHttp);
|
||||||
|
String link = text.substring(indexHttp, indexFinHttp);
|
||||||
|
String linkWithoutScheme = link.replace("https://", "");
|
||||||
|
text = text.replaceFirst(link, "<a href=\"" + link + "\">" + linkWithoutScheme + "</a>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Compatibility.fromHtml(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadBitmap(String path, ImageView imageView) {
|
||||||
|
if (cancelPotentialWork(path, imageView)) {
|
||||||
|
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
|
||||||
|
final AsyncBitmap asyncBitmap = new AsyncBitmap(context.getResources(), defaultBitmap, task);
|
||||||
|
imageView.setImageDrawable(asyncBitmap);
|
||||||
|
task.execute(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
|
||||||
|
private final WeakReference<ImageView> imageViewReference;
|
||||||
|
public String path;
|
||||||
|
|
||||||
|
public BitmapWorkerTask(ImageView imageView) {
|
||||||
|
path = null;
|
||||||
|
// Use a WeakReference to ensure the ImageView can be garbage collected
|
||||||
|
imageViewReference = new WeakReference<ImageView>(imageView);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode image in background.
|
||||||
|
@Override
|
||||||
|
protected Bitmap doInBackground(String... params) {
|
||||||
|
path = params[0];
|
||||||
|
Bitmap bm = null;
|
||||||
|
|
||||||
|
if (path.startsWith("content")) {
|
||||||
|
try {
|
||||||
|
bm = MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.parse(path));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.e(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bm = BitmapFactory.decodeFile(path);
|
||||||
|
path = "file://" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bm != null) {
|
||||||
|
bm = ThumbnailUtils.extractThumbnail(bm, SIZE_MAX, SIZE_MAX);
|
||||||
|
}
|
||||||
|
return bm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once complete, see if ImageView is still around and set bitmap.
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Bitmap bitmap) {
|
||||||
|
if (isCancelled()) {
|
||||||
|
bitmap = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageViewReference != null && bitmap != null) {
|
||||||
|
final ImageView imageView = imageViewReference.get();
|
||||||
|
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
|
||||||
|
if (this == bitmapWorkerTask && imageView != null) {
|
||||||
|
imageView.setImageBitmap(bitmap);
|
||||||
|
imageView.setTag(path);
|
||||||
|
imageView.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
intent.setDataAndType(Uri.parse((String)v.getTag()), "image/*");
|
||||||
|
context.startActivity(intent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AsyncBitmap extends BitmapDrawable {
|
||||||
|
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
|
||||||
|
|
||||||
|
public AsyncBitmap(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
|
||||||
|
super(res, bitmap);
|
||||||
|
bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitmapWorkerTask getBitmapWorkerTask() {
|
||||||
|
return bitmapWorkerTaskReference.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean cancelPotentialWork(String path, ImageView imageView) {
|
||||||
|
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
|
||||||
|
|
||||||
|
if (bitmapWorkerTask != null) {
|
||||||
|
final String bitmapData = bitmapWorkerTask.path;
|
||||||
|
// If bitmapData is not yet set or it differs from the new data
|
||||||
|
if (bitmapData == null || bitmapData != path) {
|
||||||
|
// Cancel previous task
|
||||||
|
bitmapWorkerTask.cancel(true);
|
||||||
|
} else {
|
||||||
|
// The same work is already in progress
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No task associated with the ImageView, or an existing task was cancelled
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
|
||||||
|
if (imageView != null) {
|
||||||
|
final Drawable drawable = imageView.getDrawable();
|
||||||
|
if (drawable instanceof AsyncBitmap) {
|
||||||
|
final AsyncBitmap asyncDrawable = (AsyncBitmap) drawable;
|
||||||
|
return asyncDrawable.getBitmapWorkerTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SearchContactsListAdapter extends BaseAdapter {
|
class SearchContactsListAdapter extends BaseAdapter {
|
||||||
|
private class ViewHolder {
|
||||||
|
public TextView name;
|
||||||
|
public TextView address;
|
||||||
|
|
||||||
|
public ViewHolder(View view) {
|
||||||
|
name = (TextView) view.findViewById(R.id.contact_name);
|
||||||
|
address = (TextView) view.findViewById(R.id.contact_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<ContactAddress> contacts;
|
private List<ContactAddress> contacts;
|
||||||
private LayoutInflater mInflater;
|
private LayoutInflater mInflater;
|
||||||
|
|
||||||
|
@ -1089,24 +1470,26 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
View view = null;
|
View view = null;
|
||||||
ContactAddress contact;
|
ContactAddress contact;
|
||||||
|
ViewHolder holder = null;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
contact = getItem(position);
|
contact = getItem(position);
|
||||||
} while (contact == null);
|
} while (contact == null);
|
||||||
|
|
||||||
if (convertView != null) {
|
if (convertView != null) {
|
||||||
view = convertView;
|
view = convertView;
|
||||||
|
holder = (ViewHolder) view.getTag();
|
||||||
} else {
|
} else {
|
||||||
view = mInflater.inflate(R.layout.search_contact_cell, parent, false);
|
view = mInflater.inflate(R.layout.search_contact_cell, parent, false);
|
||||||
|
holder = new ViewHolder(view);
|
||||||
|
view.setTag(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String a = contact.address;
|
final String a = contact.address;
|
||||||
LinphoneContact c = contact.contact;
|
LinphoneContact c = contact.contact;
|
||||||
|
|
||||||
TextView name = (TextView) view.findViewById(R.id.contact_name);
|
holder.name.setText(c.getFullName());
|
||||||
name.setText(c.getFullName());
|
holder.address.setText(a);
|
||||||
|
|
||||||
TextView address = (TextView) view.findViewById(R.id.contact_address);
|
|
||||||
address.setText(a);
|
|
||||||
|
|
||||||
view.setOnClickListener(new OnClickListener() {
|
view.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.linphone.mediastream.Log;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
|
@ -117,18 +118,19 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeChatsConversation(){
|
private void removeChatsConversation() {
|
||||||
int size = chatList.getAdapter().getCount();
|
int size = chatList.getAdapter().getCount();
|
||||||
for(int i=0; i<size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
if(chatList.isItemChecked(i)){
|
if (chatList.isItemChecked(i)) {
|
||||||
View item = chatList.getAdapter().getView(i, null, null);
|
String sipUri = chatList.getAdapter().getItem(i).toString();
|
||||||
if(item != null) {
|
if (sipUri != null) {
|
||||||
LinphoneChatRoom chatroom = LinphoneManager.getLc().getOrCreateChatRoom(item.getTag().toString());
|
LinphoneChatRoom chatroom = LinphoneManager.getLc().getOrCreateChatRoom(sipUri);
|
||||||
if (chatroom != null)
|
if (chatroom != null) {
|
||||||
chatroom.deleteHistory();
|
chatroom.deleteHistory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
LinphoneActivity.instance().updateMissedChatCount();
|
LinphoneActivity.instance().updateMissedChatCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +243,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
||||||
if (info == null || info.targetView == null) {
|
if (info == null || info.targetView == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String sipUri = (String) info.targetView.getTag();
|
String sipUri = chatList.getAdapter().getItem(info.position).toString();
|
||||||
|
|
||||||
LinphoneActivity.instance().removeFromChatList(sipUri);
|
LinphoneActivity.instance().removeFromChatList(sipUri);
|
||||||
mConversations = LinphoneActivity.instance().getChatList();
|
mConversations = LinphoneActivity.instance().getChatList();
|
||||||
|
@ -331,7 +333,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
|
||||||
String sipUri = (String) view.getTag();
|
String sipUri = chatList.getAdapter().getItem(position).toString();
|
||||||
|
|
||||||
if (LinphoneActivity.isInstanciated() && !isEditMode) {
|
if (LinphoneActivity.isInstanciated() && !isEditMode) {
|
||||||
LinphoneActivity.instance().displayChat(sipUri);
|
LinphoneActivity.instance().displayChat(sipUri);
|
||||||
|
@ -339,6 +341,23 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatListAdapter extends BaseAdapter {
|
class ChatListAdapter extends BaseAdapter {
|
||||||
|
private class ViewHolder {
|
||||||
|
public TextView lastMessageView;
|
||||||
|
public TextView date;
|
||||||
|
public TextView displayName;
|
||||||
|
public TextView unreadMessages;
|
||||||
|
public CheckBox select;
|
||||||
|
public ImageView contactPicture;
|
||||||
|
|
||||||
|
public ViewHolder(View view) {
|
||||||
|
lastMessageView = (TextView) view.findViewById(R.id.lastMessage);
|
||||||
|
date = (TextView) view.findViewById(R.id.date);
|
||||||
|
displayName = (TextView) view.findViewById(R.id.sipUri);
|
||||||
|
unreadMessages = (TextView) view.findViewById(R.id.unreadMessages);
|
||||||
|
select = (CheckBox) view.findViewById(R.id.delete_chatroom);
|
||||||
|
contactPicture = (ImageView) view.findViewById(R.id.contact_picture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ChatListAdapter() {}
|
ChatListAdapter() {}
|
||||||
|
|
||||||
|
@ -347,7 +366,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getItem(int position) {
|
public Object getItem(int position) {
|
||||||
return position;
|
return mConversations.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
|
@ -356,21 +375,23 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
||||||
|
|
||||||
public View getView(final int position, View convertView, ViewGroup parent) {
|
public View getView(final int position, View convertView, ViewGroup parent) {
|
||||||
View view = null;
|
View view = null;
|
||||||
|
ViewHolder holder = null;
|
||||||
|
String sipUri = mConversations.get(position);
|
||||||
|
|
||||||
if (convertView != null) {
|
if (convertView != null) {
|
||||||
view = convertView;
|
view = convertView;
|
||||||
|
holder = (ViewHolder) view.getTag();
|
||||||
} else {
|
} else {
|
||||||
view = mInflater.inflate(R.layout.chatlist_cell, parent, false);
|
view = mInflater.inflate(R.layout.chatlist_cell, parent, false);
|
||||||
|
holder = new ViewHolder(view);
|
||||||
|
view.setTag(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
String sipUri = mConversations.get(position);
|
|
||||||
view.setTag(sipUri);
|
|
||||||
|
|
||||||
LinphoneAddress address;
|
LinphoneAddress address;
|
||||||
try {
|
try {
|
||||||
address = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri);
|
address = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri);
|
||||||
} catch (LinphoneCoreException e) {
|
} catch (LinphoneCoreException e) {
|
||||||
Log.e("Chat view cannot parse address",e);
|
Log.e("Chat view cannot parse address", e);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,57 +399,55 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
||||||
String message = "";
|
String message = "";
|
||||||
Long time;
|
Long time;
|
||||||
|
|
||||||
TextView lastMessageView = (TextView) view.findViewById(R.id.lastMessage);
|
|
||||||
TextView date = (TextView) view.findViewById(R.id.date);
|
|
||||||
TextView displayName = (TextView) view.findViewById(R.id.sipUri);
|
|
||||||
TextView unreadMessages = (TextView) view.findViewById(R.id.unreadMessages);
|
|
||||||
CheckBox select = (CheckBox) view.findViewById(R.id.delete_chatroom);
|
|
||||||
ImageView contactPicture = (ImageView) view.findViewById(R.id.contact_picture);
|
|
||||||
|
|
||||||
LinphoneChatRoom chatRoom = LinphoneManager.getLc().getChatRoom(address);
|
LinphoneChatRoom chatRoom = LinphoneManager.getLc().getChatRoom(address);
|
||||||
int unreadMessagesCount = chatRoom.getUnreadMessagesCount();
|
int unreadMessagesCount = chatRoom.getUnreadMessagesCount();
|
||||||
LinphoneChatMessage[] history = chatRoom.getHistory(1);
|
LinphoneChatMessage[] history = chatRoom.getHistory(1);
|
||||||
LinphoneChatMessage msg = history[0];
|
LinphoneChatMessage msg = history[0];
|
||||||
|
|
||||||
if(msg.getFileTransferInformation() != null || msg.getExternalBodyUrl() != null || msg.getAppData() != null ){
|
if(msg.getFileTransferInformation() != null || msg.getExternalBodyUrl() != null || msg.getAppData() != null ){
|
||||||
lastMessageView.setBackgroundResource(R.drawable.chat_file_message);
|
holder.lastMessageView.setBackgroundResource(R.drawable.chat_file_message);
|
||||||
time = msg.getTime();
|
time = msg.getTime();
|
||||||
date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format)));
|
holder.date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format)));
|
||||||
lastMessageView.setText("");
|
holder.lastMessageView.setText("");
|
||||||
} else if (msg.getText() != null && msg.getText().length() > 0 ){
|
} else if (msg.getText() != null && msg.getText().length() > 0 ){
|
||||||
message = msg.getText();
|
message = msg.getText();
|
||||||
lastMessageView.setBackgroundResource(0);
|
holder.lastMessageView.setBackgroundResource(0);
|
||||||
time = msg.getTime();
|
time = msg.getTime();
|
||||||
date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format)));
|
holder.date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format)));
|
||||||
lastMessageView.setText(message);
|
holder.lastMessageView.setText(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
displayName.setSelected(true); // For animation
|
holder.displayName.setSelected(true); // For animation
|
||||||
displayName.setText(contact == null ? LinphoneUtils.getAddressDisplayName(address) : contact.getFullName());
|
holder.displayName.setText(contact == null ? LinphoneUtils.getAddressDisplayName(address) : contact.getFullName());
|
||||||
|
|
||||||
|
|
||||||
if (contact != null) {
|
if (contact != null) {
|
||||||
LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
|
Bitmap photo = contact.getPhoto();
|
||||||
|
if (photo != null) {
|
||||||
|
holder.contactPicture.setImageBitmap(photo);
|
||||||
} else {
|
} else {
|
||||||
contactPicture.setImageResource(R.drawable.avatar);
|
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.contactPicture.setImageResource(R.drawable.avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unreadMessagesCount > 0) {
|
if (unreadMessagesCount > 0) {
|
||||||
unreadMessages.setVisibility(View.VISIBLE);
|
holder.unreadMessages.setVisibility(View.VISIBLE);
|
||||||
unreadMessages.setText(String.valueOf(unreadMessagesCount));
|
holder.unreadMessages.setText(String.valueOf(unreadMessagesCount));
|
||||||
if(unreadMessagesCount > 99){
|
if (unreadMessagesCount > 99) {
|
||||||
unreadMessages.setTextSize(12);
|
holder.unreadMessages.setTextSize(12);
|
||||||
}
|
}
|
||||||
displayName.setTypeface(null, Typeface.BOLD);
|
holder.displayName.setTypeface(null, Typeface.BOLD);
|
||||||
} else {
|
} else {
|
||||||
unreadMessages.setVisibility(View.GONE);
|
holder.unreadMessages.setVisibility(View.GONE);
|
||||||
displayName.setTypeface(null, Typeface.NORMAL);
|
holder.displayName.setTypeface(null, Typeface.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEditMode) {
|
if (isEditMode) {
|
||||||
unreadMessages.setVisibility(View.GONE);
|
holder.unreadMessages.setVisibility(View.GONE);
|
||||||
select.setVisibility(View.VISIBLE);
|
holder.select.setVisibility(View.VISIBLE);
|
||||||
select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
holder.select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||||
chatList.setItemChecked(position, b);
|
chatList.setItemChecked(position, b);
|
||||||
|
@ -450,13 +469,13 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(chatList.isItemChecked(position)) {
|
if(chatList.isItemChecked(position)) {
|
||||||
select.setChecked(true);
|
holder.select.setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
select.setChecked(false);
|
holder.select.setChecked(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (unreadMessagesCount > 0) {
|
if (unreadMessagesCount > 0) {
|
||||||
unreadMessages.setVisibility(View.VISIBLE);
|
holder.unreadMessages.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
package org.linphone;
|
|
||||||
|
|
||||||
import org.linphone.core.LinphoneChatMessage;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
/*
|
|
||||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sylvain Berfini
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public class ChatMessage {
|
|
||||||
private String message;
|
|
||||||
private String timestamp;
|
|
||||||
private String url;
|
|
||||||
private boolean incoming;
|
|
||||||
private int status;
|
|
||||||
private int id;
|
|
||||||
private Bitmap image;
|
|
||||||
private boolean isRead;
|
|
||||||
|
|
||||||
public ChatMessage(int id, String message, byte[] rawImage, String timestamp, boolean incoming, int status, boolean read) {
|
|
||||||
super();
|
|
||||||
this.id = id;
|
|
||||||
this.message = message;
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
this.incoming = incoming;
|
|
||||||
this.status = status;
|
|
||||||
this.image = rawImage != null ? BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length) : null;
|
|
||||||
this.isRead = read;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChatMessage(int id, String message, Bitmap image, String timestamp, boolean incoming, int status, boolean read) {
|
|
||||||
super();
|
|
||||||
this.id = id;
|
|
||||||
this.message = message;
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
this.incoming = incoming;
|
|
||||||
this.status = status;
|
|
||||||
this.image = image;
|
|
||||||
this.isRead = read;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(int status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LinphoneChatMessage.State getStatus() {
|
|
||||||
return LinphoneChatMessage.State.fromInt(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bitmap getImage() {
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRead() {
|
|
||||||
return isRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return this.id + " : " + this.message + " (" + this.url + ") @ " + this.timestamp + ", read= " + this.isRead + ", incoming= " + this.incoming + ", status = " + this.status;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.compatibility.Compatibility;
|
|
||||||
import org.linphone.core.LinphoneAddress;
|
|
||||||
import org.linphone.core.LinphoneCore;
|
|
||||||
import org.linphone.core.LinphoneFriend;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sylvain Berfini
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public class Contact implements Serializable {
|
|
||||||
private static final long serialVersionUID = 3790717505065723499L;
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String name;
|
|
||||||
private transient Uri photoUri;
|
|
||||||
private transient Uri thumbnailUri;
|
|
||||||
private transient Bitmap photo;
|
|
||||||
private List<String> numbersOrAddresses;
|
|
||||||
private boolean hasFriends;
|
|
||||||
private LinphoneAddress address;
|
|
||||||
|
|
||||||
public Contact(String id, String name) {
|
|
||||||
super();
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.photoUri = null;
|
|
||||||
this.thumbnailUri = null;
|
|
||||||
this.hasFriends = false;
|
|
||||||
this.address = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Contact(String id, LinphoneAddress address) {
|
|
||||||
super();
|
|
||||||
this.id = id;
|
|
||||||
this.name = LinphoneUtils.getAddressDisplayName(address);
|
|
||||||
this.photoUri = null;
|
|
||||||
this.thumbnailUri = null;
|
|
||||||
this.address = address;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Contact(String id, String name, Uri photo, Uri thumbnail) {
|
|
||||||
super();
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.photoUri = photo;
|
|
||||||
this.thumbnailUri = thumbnail;
|
|
||||||
this.photo = null;
|
|
||||||
this.hasFriends = false;
|
|
||||||
this.address = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Contact(String id, String name, Uri photo, Uri thumbnail, Bitmap picture) {
|
|
||||||
super();
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.photoUri = photo;
|
|
||||||
this.thumbnailUri = thumbnail;
|
|
||||||
this.photo = picture;
|
|
||||||
this.hasFriends = false;
|
|
||||||
this.address = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean hasFriends() {
|
|
||||||
return hasFriends;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getID() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LinphoneAddress getLinphoneAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uri getPhotoUri() {
|
|
||||||
return photoUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uri getThumbnailUri() {
|
|
||||||
return thumbnailUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bitmap getPhoto() {
|
|
||||||
return photo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getNumbersOrAddresses() {
|
|
||||||
if (numbersOrAddresses == null)
|
|
||||||
numbersOrAddresses = new ArrayList<String>();
|
|
||||||
return numbersOrAddresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refresh(ContentResolver cr) {
|
|
||||||
this.numbersOrAddresses = Compatibility.extractContactNumbersAndAddresses(id, cr);
|
|
||||||
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
|
||||||
if(lc != null && lc.getFriendList() != null) {
|
|
||||||
for (LinphoneFriend friend :lc.getFriendList()){
|
|
||||||
if (id.equals(friend.getRefKey())) {
|
|
||||||
hasFriends = true;
|
|
||||||
this.numbersOrAddresses.add(friend.getAddress().asStringUriOnly());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.name = Compatibility.refreshContactName(cr, id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -78,8 +78,9 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
|
||||||
deleteContact.setOnClickListener(this);
|
deleteContact.setOnClickListener(this);
|
||||||
|
|
||||||
organization = (TextView) view.findViewById(R.id.contactOrganization);
|
organization = (TextView) view.findViewById(R.id.contactOrganization);
|
||||||
|
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
|
||||||
String org = contact.getOrganization();
|
String org = contact.getOrganization();
|
||||||
if (org != null && !org.isEmpty()) {
|
if (org != null && !org.isEmpty() && isOrgVisible) {
|
||||||
organization.setText(org);
|
organization.setText(org);
|
||||||
} else {
|
} else {
|
||||||
organization.setVisibility(View.GONE);
|
organization.setVisibility(View.GONE);
|
||||||
|
|
|
@ -204,10 +204,17 @@ public class ContactEditorFragment extends Fragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
organization = (EditText) view.findViewById(R.id.contactOrganization);
|
organization = (EditText) view.findViewById(R.id.contactOrganization);
|
||||||
|
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
|
||||||
|
if (!isOrgVisible) {
|
||||||
|
organization.setVisibility(View.GONE);
|
||||||
|
view.findViewById(R.id.contactOrganizationTitle).setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
if (!isNewContact) {
|
if (!isNewContact) {
|
||||||
organization.setText(contact.getOrganization());
|
organization.setText(contact.getOrganization());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isNewContact) {
|
if (!isNewContact) {
|
||||||
String fn = contact.getFirstName();
|
String fn = contact.getFirstName();
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.linphone.core.PresenceActivityType;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
@ -416,6 +417,28 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContactsListAdapter extends BaseAdapter implements SectionIndexer {
|
class ContactsListAdapter extends BaseAdapter implements SectionIndexer {
|
||||||
|
private class ViewHolder {
|
||||||
|
public CheckBox delete;
|
||||||
|
public ImageView linphoneFriend;
|
||||||
|
public TextView name;
|
||||||
|
public LinearLayout separator;
|
||||||
|
public TextView separatorText;
|
||||||
|
public ImageView contactPicture;
|
||||||
|
public TextView organization;
|
||||||
|
public ImageView friendStatus;
|
||||||
|
|
||||||
|
public ViewHolder(View view) {
|
||||||
|
delete = (CheckBox) view.findViewById(R.id.delete);
|
||||||
|
linphoneFriend = (ImageView) view.findViewById(R.id.friendLinphone);
|
||||||
|
name = (TextView) view.findViewById(R.id.name);
|
||||||
|
separator = (LinearLayout) view.findViewById(R.id.separator);
|
||||||
|
separatorText = (TextView) view.findViewById(R.id.separator_text);
|
||||||
|
contactPicture = (ImageView) view.findViewById(R.id.contact_picture);
|
||||||
|
organization = (TextView) view.findViewById(R.id.contactOrganization);
|
||||||
|
friendStatus = (ImageView) view.findViewById(R.id.friendStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<LinphoneContact> contacts;
|
private List<LinphoneContact> contacts;
|
||||||
String[] sections;
|
String[] sections;
|
||||||
ArrayList<String> sectionsList;
|
ArrayList<String> sectionsList;
|
||||||
|
@ -461,57 +484,57 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O
|
||||||
LinphoneContact contact = (LinphoneContact) getItem(position);
|
LinphoneContact contact = (LinphoneContact) getItem(position);
|
||||||
if (contact == null) return null;
|
if (contact == null) return null;
|
||||||
|
|
||||||
|
ViewHolder holder = null;
|
||||||
if (convertView != null) {
|
if (convertView != null) {
|
||||||
view = convertView;
|
view = convertView;
|
||||||
|
holder = (ViewHolder) view.getTag();
|
||||||
} else {
|
} else {
|
||||||
view = mInflater.inflate(R.layout.contact_cell, parent, false);
|
view = mInflater.inflate(R.layout.contact_cell, parent, false);
|
||||||
|
holder = new ViewHolder(view);
|
||||||
|
view.setTag(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox delete = (CheckBox) view.findViewById(R.id.delete);
|
holder.name.setText(contact.getFullName());
|
||||||
ImageView linphoneFriend = (ImageView) view.findViewById(R.id.friendLinphone);
|
|
||||||
|
|
||||||
TextView name = (TextView) view.findViewById(R.id.name);
|
|
||||||
name.setText(contact.getFullName());
|
|
||||||
|
|
||||||
LinearLayout separator = (LinearLayout) view.findViewById(R.id.separator);
|
|
||||||
TextView separatorText = (TextView) view.findViewById(R.id.separator_text);
|
|
||||||
if (getPositionForSection(getSectionForPosition(position)) != position) {
|
if (getPositionForSection(getSectionForPosition(position)) != position) {
|
||||||
separator.setVisibility(View.GONE);
|
holder.separator.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
separator.setVisibility(View.VISIBLE);
|
holder.separator.setVisibility(View.VISIBLE);
|
||||||
String fullName = contact.getFullName();
|
String fullName = contact.getFullName();
|
||||||
if (fullName != null && !fullName.isEmpty()) {
|
if (fullName != null && !fullName.isEmpty()) {
|
||||||
separatorText.setText(String.valueOf(fullName.charAt(0)));
|
holder.separatorText.setText(String.valueOf(fullName.charAt(0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contact.isInLinphoneFriendList()) {
|
if (contact.isInLinphoneFriendList()) {
|
||||||
linphoneFriend.setVisibility(View.VISIBLE);
|
holder.linphoneFriend.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
linphoneFriend.setVisibility(View.GONE);
|
holder.linphoneFriend.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageView icon = (ImageView) view.findViewById(R.id.contact_picture);
|
|
||||||
if (contact.hasPhoto()) {
|
if (contact.hasPhoto()) {
|
||||||
LinphoneUtils.setImagePictureFromUri(getActivity(), icon, contact.getPhotoUri(), contact.getThumbnailUri());
|
Bitmap photo = contact.getPhoto();
|
||||||
} else if (contact.getPhotoUri() != null) {
|
if (photo != null) {
|
||||||
icon.setImageURI(contact.getPhotoUri());
|
holder.contactPicture.setImageBitmap(photo);
|
||||||
} else {
|
} else {
|
||||||
icon.setImageResource(R.drawable.avatar);
|
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
holder.contactPicture.setImageResource(R.drawable.avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextView organization = (TextView) view.findViewById(R.id.contactOrganization);
|
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
|
||||||
String org = contact.getOrganization();
|
String org = contact.getOrganization();
|
||||||
if (org != null && !org.isEmpty()) {
|
if (org != null && !org.isEmpty() && isOrgVisible) {
|
||||||
organization.setText(org);
|
holder.organization.setText(org);
|
||||||
organization.setVisibility(View.VISIBLE);
|
holder.organization.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
organization.setVisibility(View.GONE);
|
holder.organization.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEditMode) {
|
if (isEditMode) {
|
||||||
delete.setVisibility(View.VISIBLE);
|
holder.delete.setVisibility(View.VISIBLE);
|
||||||
delete.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
holder.delete.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||||
contactsList.setItemChecked(position, b);
|
contactsList.setItemChecked(position, b);
|
||||||
|
@ -533,29 +556,28 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (contactsList.isItemChecked(position)) {
|
if (contactsList.isItemChecked(position)) {
|
||||||
delete.setChecked(true);
|
holder.delete.setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
delete.setChecked(false);
|
holder.delete.setChecked(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
delete.setVisibility(View.GONE);
|
holder.delete.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageView friendStatus = (ImageView) view.findViewById(R.id.friendStatus);
|
|
||||||
LinphoneFriend[] friends = LinphoneManager.getLc().getFriendList();
|
LinphoneFriend[] friends = LinphoneManager.getLc().getFriendList();
|
||||||
if (!ContactsManager.getInstance().isContactPresenceDisabled() && friends != null) {
|
if (!ContactsManager.getInstance().isContactPresenceDisabled() && friends != null) {
|
||||||
friendStatus.setVisibility(View.VISIBLE);
|
holder.friendStatus.setVisibility(View.VISIBLE);
|
||||||
PresenceActivityType presenceActivity = friends[0].getPresenceModel().getActivity().getType();
|
PresenceActivityType presenceActivity = friends[0].getPresenceModel().getActivity().getType();
|
||||||
if (presenceActivity == PresenceActivityType.Online) {
|
if (presenceActivity == PresenceActivityType.Online) {
|
||||||
friendStatus.setImageResource(R.drawable.led_connected);
|
holder.friendStatus.setImageResource(R.drawable.led_connected);
|
||||||
} else if (presenceActivity == PresenceActivityType.Busy) {
|
} else if (presenceActivity == PresenceActivityType.Busy) {
|
||||||
friendStatus.setImageResource(R.drawable.led_error);
|
holder.friendStatus.setImageResource(R.drawable.led_error);
|
||||||
} else if (presenceActivity == PresenceActivityType.Away) {
|
} else if (presenceActivity == PresenceActivityType.Away) {
|
||||||
friendStatus.setImageResource(R.drawable.led_inprogress);
|
holder.friendStatus.setImageResource(R.drawable.led_inprogress);
|
||||||
} else if (presenceActivity == PresenceActivityType.Offline) {
|
} else if (presenceActivity == PresenceActivityType.Offline) {
|
||||||
friendStatus.setImageResource(R.drawable.led_disconnected);
|
holder.friendStatus.setImageResource(R.drawable.led_disconnected);
|
||||||
} else {
|
} else {
|
||||||
friendStatus.setImageResource(R.drawable.call_quality_indicator_0);
|
holder.friendStatus.setImageResource(R.drawable.call_quality_indicator_0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,11 @@ package org.linphone;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.linphone.compatibility.Compatibility;
|
|
||||||
import org.linphone.core.LinphoneAddress;
|
import org.linphone.core.LinphoneAddress;
|
||||||
import org.linphone.core.LinphoneCore;
|
import org.linphone.core.LinphoneCore;
|
||||||
import org.linphone.core.LinphoneFriend;
|
import org.linphone.core.LinphoneFriend;
|
||||||
|
@ -38,11 +39,13 @@ import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.database.MatrixCursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
|
import android.provider.ContactsContract.CommonDataKinds;
|
||||||
import android.provider.ContactsContract.Data;
|
import android.provider.ContactsContract.Data;
|
||||||
|
|
||||||
interface ContactsUpdatedListener {
|
interface ContactsUpdatedListener {
|
||||||
|
@ -228,14 +231,13 @@ public class ContactsManager extends ContentObserver {
|
||||||
contactsFetchTask.execute();
|
contactsFetchTask.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class ContactsFetchTask extends AsyncTask<Void, List<LinphoneContact>, List<LinphoneContact>> {
|
private class ContactsFetchTask extends AsyncTask<Void, List<LinphoneContact>, List<LinphoneContact>> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected List<LinphoneContact> doInBackground(Void... params) {
|
protected List<LinphoneContact> doInBackground(Void... params) {
|
||||||
List<LinphoneContact> contacts = new ArrayList<LinphoneContact>();
|
List<LinphoneContact> contacts = new ArrayList<LinphoneContact>();
|
||||||
|
|
||||||
if (hasContactsAccess()) {
|
if (hasContactsAccess()) {
|
||||||
Cursor c = Compatibility.getContactsCursor(contentResolver, null);
|
Cursor c = getContactsCursor(contentResolver);
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
while (c.moveToNext()) {
|
while (c.moveToNext()) {
|
||||||
String id = c.getString(c.getColumnIndex(Data.CONTACT_ID));
|
String id = c.getString(c.getColumnIndex(Data.CONTACT_ID));
|
||||||
|
@ -367,4 +369,38 @@ public class ContactsManager extends ContentObserver {
|
||||||
public String getString(int resourceID) {
|
public String getString(int resourceID) {
|
||||||
return context.getString(resourceID);
|
return context.getString(resourceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Cursor getContactsCursor(ContentResolver cr) {
|
||||||
|
String req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
||||||
|
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL "
|
||||||
|
+ " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
||||||
|
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL))";
|
||||||
|
String[] projection = new String[] { Data.CONTACT_ID, Data.DISPLAY_NAME };
|
||||||
|
String query = Data.DISPLAY_NAME + " IS NOT NULL AND (" + req + ")";
|
||||||
|
|
||||||
|
Cursor cursor = cr.query(Data.CONTENT_URI, projection, query, null, " lower(" + Data.DISPLAY_NAME + ") COLLATE UNICODE ASC");
|
||||||
|
if (cursor == null) {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatrixCursor result = new MatrixCursor(cursor.getColumnNames());
|
||||||
|
Set<String> groupBy = new HashSet<String>();
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
String name = cursor.getString(cursor.getColumnIndex(Data.DISPLAY_NAME));
|
||||||
|
if (!groupBy.contains(name)) {
|
||||||
|
groupBy.add(name);
|
||||||
|
Object[] newRow = new Object[cursor.getColumnCount()];
|
||||||
|
|
||||||
|
int contactID = cursor.getColumnIndex(Data.CONTACT_ID);
|
||||||
|
int displayName = cursor.getColumnIndex(Data.DISPLAY_NAME);
|
||||||
|
|
||||||
|
newRow[contactID] = cursor.getString(contactID);
|
||||||
|
newRow[displayName] = cursor.getString(displayName);
|
||||||
|
|
||||||
|
result.addRow(newRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.linphone.core.LinphoneCallLog.CallStatus;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -349,6 +350,22 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
||||||
}
|
}
|
||||||
|
|
||||||
class CallHistoryAdapter extends BaseAdapter {
|
class CallHistoryAdapter extends BaseAdapter {
|
||||||
|
private class ViewHolder {
|
||||||
|
public TextView contact;
|
||||||
|
public ImageView detail;
|
||||||
|
public CheckBox select;
|
||||||
|
public ImageView callDirection;
|
||||||
|
public ImageView contactPicture;
|
||||||
|
|
||||||
|
public ViewHolder(View view) {
|
||||||
|
contact = (TextView) view.findViewById(R.id.sip_uri);
|
||||||
|
detail = (ImageView) view.findViewById(R.id.detail);
|
||||||
|
select = (CheckBox) view.findViewById(R.id.delete);
|
||||||
|
callDirection = (ImageView) view.findViewById(R.id.icon);
|
||||||
|
contactPicture = (ImageView) view.findViewById(R.id.contact_picture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CallHistoryAdapter(Context aContext) {
|
CallHistoryAdapter(Context aContext) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -401,23 +418,20 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
||||||
|
|
||||||
public View getView(final int position, View convertView, ViewGroup parent) {
|
public View getView(final int position, View convertView, ViewGroup parent) {
|
||||||
View view = null;
|
View view = null;
|
||||||
ViewHolder holder;
|
ViewHolder holder = null;
|
||||||
|
|
||||||
if (convertView != null) {
|
if (convertView != null) {
|
||||||
view = convertView;
|
view = convertView;
|
||||||
holder = (ViewHolder) view.getTag();
|
holder = (ViewHolder) view.getTag();
|
||||||
} else {
|
} else {
|
||||||
view = mInflater.inflate(R.layout.history_cell, parent,false);
|
view = mInflater.inflate(R.layout.history_cell, parent,false);
|
||||||
holder = new ViewHolder();
|
holder = new ViewHolder(view);
|
||||||
holder.contact = (TextView) view.findViewById(R.id.sip_uri);
|
view.setTag(holder);
|
||||||
holder.detail = (ImageView) view.findViewById(R.id.detail);
|
|
||||||
holder.select = (CheckBox) view.findViewById(R.id.delete);
|
|
||||||
holder.callDirection = (ImageView) view.findViewById(R.id.icon);
|
|
||||||
holder.contactPicture = (ImageView) view.findViewById(R.id.contact_picture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final LinphoneCallLog log = mLogs.get(position);
|
final LinphoneCallLog log = mLogs.get(position);
|
||||||
long timestamp = log.getTimestamp();
|
long timestamp = log.getTimestamp();
|
||||||
final LinphoneAddress address;
|
LinphoneAddress address;
|
||||||
|
|
||||||
holder.contact.setSelected(true); // For automated horizontal scrolling of long texts
|
holder.contact.setSelected(true); // For automated horizontal scrolling of long texts
|
||||||
|
|
||||||
|
@ -457,9 +471,18 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
||||||
LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address);
|
LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address);
|
||||||
String displayName = null;
|
String displayName = null;
|
||||||
final String sipUri = address.asString();
|
final String sipUri = address.asString();
|
||||||
if(c != null){
|
if (c != null) {
|
||||||
displayName = c.getFullName();
|
displayName = c.getFullName();
|
||||||
LinphoneUtils.setImagePictureFromUri(view.getContext(),holder.contactPicture,c.getPhotoUri(),c.getThumbnailUri());
|
if (c.hasPhoto()) {
|
||||||
|
Bitmap photo = c.getPhoto();
|
||||||
|
if (photo != null) {
|
||||||
|
holder.contactPicture.setImageBitmap(photo);
|
||||||
|
} else {
|
||||||
|
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, c.getPhotoUri(), c.getThumbnailUri());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, c.getPhotoUri(), c.getThumbnailUri());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
holder.contactPicture.setImageResource(R.drawable.avatar);
|
holder.contactPicture.setImageResource(R.drawable.avatar);
|
||||||
}
|
}
|
||||||
|
@ -469,7 +492,6 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
||||||
} else {
|
} else {
|
||||||
holder.contact.setText(displayName);
|
holder.contact.setText(displayName);
|
||||||
}
|
}
|
||||||
//view.setTag(sipUri);
|
|
||||||
|
|
||||||
if (isEditMode) {
|
if (isEditMode) {
|
||||||
holder.select.setVisibility(View.VISIBLE);
|
holder.select.setVisibility(View.VISIBLE);
|
||||||
|
@ -512,16 +534,7 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
view.setTag(holder);
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ViewHolder {
|
|
||||||
TextView contact;
|
|
||||||
ImageView detail;
|
|
||||||
CheckBox select;
|
|
||||||
ImageView callDirection;
|
|
||||||
ImageView contactPicture;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -110,6 +110,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
|
||||||
private static final int PERMISSIONS_REQUEST_CONTACTS = 208;
|
private static final int PERMISSIONS_REQUEST_CONTACTS = 208;
|
||||||
private static final int PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER = 209;
|
private static final int PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER = 209;
|
||||||
private static final int PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE = 210;
|
private static final int PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE = 210;
|
||||||
|
private static final int PERMISSIONS_RECORD_AUDIO_ECHO_TESTER = 211;
|
||||||
|
|
||||||
private static LinphoneActivity instance;
|
private static LinphoneActivity instance;
|
||||||
|
|
||||||
|
@ -1191,6 +1192,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
|
||||||
checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER);
|
checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkAndRequestRecordAudioPermissionsForEchoTester() {
|
||||||
|
checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, PERMISSIONS_RECORD_AUDIO_ECHO_TESTER);
|
||||||
|
}
|
||||||
|
|
||||||
public void checkAndRequestReadExternalStoragePermissionForDeviceRingtone() {
|
public void checkAndRequestReadExternalStoragePermissionForDeviceRingtone() {
|
||||||
checkAndRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE);
|
checkAndRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE);
|
||||||
}
|
}
|
||||||
|
@ -1269,6 +1274,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
|
||||||
case PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE:
|
case PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE:
|
||||||
((SettingsFragment) fragment).enableDeviceRingtone(grantResults[0] == PackageManager.PERMISSION_GRANTED);
|
((SettingsFragment) fragment).enableDeviceRingtone(grantResults[0] == PackageManager.PERMISSION_GRANTED);
|
||||||
break;
|
break;
|
||||||
|
case PERMISSIONS_RECORD_AUDIO_ECHO_TESTER:
|
||||||
|
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||||
|
((SettingsFragment) fragment).startEchoTester();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
package org.linphone;
|
package org.linphone;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -38,8 +40,10 @@ import android.content.ContentResolver;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
|
import android.provider.MediaStore;
|
||||||
import android.provider.ContactsContract.CommonDataKinds;
|
import android.provider.ContactsContract.CommonDataKinds;
|
||||||
|
|
||||||
public class LinphoneContact implements Serializable, Comparable<LinphoneContact> {
|
public class LinphoneContact implements Serializable, Comparable<LinphoneContact> {
|
||||||
|
@ -55,6 +59,7 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
||||||
private transient ArrayList<ContentProviderOperation> changesToCommit;
|
private transient ArrayList<ContentProviderOperation> changesToCommit;
|
||||||
private transient ArrayList<ContentProviderOperation> changesToCommit2;
|
private transient ArrayList<ContentProviderOperation> changesToCommit2;
|
||||||
private boolean hasSipAddress;
|
private boolean hasSipAddress;
|
||||||
|
private Bitmap photoBitmap, thumbnailBitmap;
|
||||||
|
|
||||||
public LinphoneContact() {
|
public LinphoneContact() {
|
||||||
addresses = new ArrayList<LinphoneNumberOrAddress>();
|
addresses = new ArrayList<LinphoneNumberOrAddress>();
|
||||||
|
@ -66,6 +71,19 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
||||||
hasSipAddress = false;
|
hasSipAddress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
if (photoBitmap != null) {
|
||||||
|
photoBitmap.recycle();
|
||||||
|
photoBitmap = null;
|
||||||
|
}
|
||||||
|
if (thumbnailBitmap != null) {
|
||||||
|
thumbnailBitmap.recycle();
|
||||||
|
thumbnailBitmap = null;
|
||||||
|
}
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(LinphoneContact contact) {
|
public int compareTo(LinphoneContact contact) {
|
||||||
String fullName = getFullName();
|
String fullName = getFullName();
|
||||||
|
@ -167,21 +185,62 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPhotoUri(Uri uri) {
|
public void setPhotoUri(Uri uri) {
|
||||||
|
if (uri.equals(photoUri)) return;
|
||||||
photoUri = uri;
|
photoUri = uri;
|
||||||
|
|
||||||
|
if (photoBitmap != null) {
|
||||||
|
photoBitmap.recycle();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
photoBitmap = MediaStore.Images.Media.getBitmap(ContactsManager.getInstance().getContentResolver(), photoUri);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
// Let's not say anything if the picture doesn't exist, it will pollute the logs
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getPhotoUri() {
|
public Uri getPhotoUri() {
|
||||||
return photoUri;
|
return photoUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Bitmap getPhotoBitmap() {
|
||||||
|
return photoBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
public void setThumbnailUri(Uri uri) {
|
public void setThumbnailUri(Uri uri) {
|
||||||
|
if (uri.equals(thumbnailUri)) return;
|
||||||
thumbnailUri = uri;
|
thumbnailUri = uri;
|
||||||
|
|
||||||
|
if (thumbnailBitmap != null) {
|
||||||
|
thumbnailBitmap.recycle();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
thumbnailBitmap = MediaStore.Images.Media.getBitmap(ContactsManager.getInstance().getContentResolver(), thumbnailUri);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
// Let's not say anything if the picture doesn't exist, it will pollute the logs
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getThumbnailUri() {
|
public Uri getThumbnailUri() {
|
||||||
return thumbnailUri;
|
return thumbnailUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Bitmap getThumbnailBitmap() {
|
||||||
|
return thumbnailBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap getPhoto() {
|
||||||
|
if (photoBitmap != null) {
|
||||||
|
return photoBitmap;
|
||||||
|
} else if (thumbnailBitmap != null) {
|
||||||
|
return thumbnailBitmap;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void setPhoto(byte[] photo) {
|
public void setPhoto(byte[] photo) {
|
||||||
if (photo != null) {
|
if (photo != null) {
|
||||||
if (isAndroidContact()) {
|
if (isAndroidContact()) {
|
||||||
|
@ -419,6 +478,7 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
||||||
friend.edit();
|
friend.edit();
|
||||||
friend.setFamilyName(lastName);
|
friend.setFamilyName(lastName);
|
||||||
friend.setGivenName(firstName);
|
friend.setGivenName(firstName);
|
||||||
|
friend.setName(fullName);
|
||||||
|
|
||||||
for (LinphoneAddress address : friend.getAddresses()) {
|
for (LinphoneAddress address : friend.getAddresses()) {
|
||||||
friend.removeAddress(address);
|
friend.removeAddress(address);
|
||||||
|
@ -443,24 +503,20 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
||||||
friend.addPhoneNumber(noa.getValue());
|
friend.addPhoneNumber(noa.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (friend.getAddress() != null) {
|
|
||||||
friend.setName(fullName);
|
|
||||||
}
|
|
||||||
friend.done();
|
friend.done();
|
||||||
|
|
||||||
if (friend.getAddress() != null) {
|
if (!friend.isAlreadyPresentInFriendList()) {
|
||||||
if (lc.findFriendByAddress(friend.getAddress().asString()) == null) {
|
|
||||||
try {
|
try {
|
||||||
lc.addFriend(friend);
|
LinphoneManager.getLcIfManagerNotDestroyedOrNull().addFriend(friend);
|
||||||
if (!ContactsManager.getInstance().hasContactsAccess()) {
|
|
||||||
// This refresh is only needed if app has no contacts permission to refresh the list of LinphoneFriends.
|
|
||||||
// Otherwise contacts will be refreshed due to changes in native contact and the handler in ContactsManager
|
|
||||||
ContactsManager.getInstance().fetchContactsAsync();
|
|
||||||
}
|
|
||||||
} catch (LinphoneCoreException e) {
|
} catch (LinphoneCoreException e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ContactsManager.getInstance().hasContactsAccess()) {
|
||||||
|
// This refresh is only needed if app has no contacts permission to refresh the list of LinphoneFriends.
|
||||||
|
// Otherwise contacts will be refreshed due to changes in native contact and the handler in ContactsManager
|
||||||
|
ContactsManager.getInstance().fetchContactsAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,10 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import org.linphone.compatibility.Compatibility;
|
|
||||||
import org.linphone.core.CallDirection;
|
import org.linphone.core.CallDirection;
|
||||||
import org.linphone.core.LinphoneAddress;
|
import org.linphone.core.LinphoneAddress;
|
||||||
import org.linphone.core.LinphoneBuffer;
|
import org.linphone.core.LinphoneBuffer;
|
||||||
|
@ -77,7 +74,6 @@ import org.linphone.tools.OpenH264DownloadHelper;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
@ -87,10 +83,6 @@ import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.hardware.Sensor;
|
|
||||||
import android.hardware.SensorEvent;
|
|
||||||
import android.hardware.SensorEventListener;
|
|
||||||
import android.hardware.SensorManager;
|
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
|
@ -105,10 +97,6 @@ import android.preference.CheckBoxPreference;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.provider.Settings.SettingNotFoundException;
|
import android.provider.Settings.SettingNotFoundException;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,6 +129,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
private String basePath;
|
private String basePath;
|
||||||
private static boolean sExited;
|
private static boolean sExited;
|
||||||
private boolean mAudioFocused;
|
private boolean mAudioFocused;
|
||||||
|
private boolean echoTesterIsRunning;
|
||||||
private int mLastNetworkType=-1;
|
private int mLastNetworkType=-1;
|
||||||
private ConnectivityManager mConnectivityManager;
|
private ConnectivityManager mConnectivityManager;
|
||||||
private BroadcastReceiver mKeepAliveReceiver;
|
private BroadcastReceiver mKeepAliveReceiver;
|
||||||
|
@ -164,6 +153,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
|
|
||||||
protected LinphoneManager(final Context c) {
|
protected LinphoneManager(final Context c) {
|
||||||
sExited = false;
|
sExited = false;
|
||||||
|
echoTesterIsRunning = false;
|
||||||
mServiceContext = c;
|
mServiceContext = c;
|
||||||
basePath = c.getFilesDir().getAbsolutePath();
|
basePath = c.getFilesDir().getAbsolutePath();
|
||||||
mLPConfigXsd = basePath + "/lpconfig.xsd";
|
mLPConfigXsd = basePath + "/lpconfig.xsd";
|
||||||
|
@ -217,8 +207,8 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
mCodecDownloader = LinphoneCoreFactory.instance().createOpenH264DownloadHelper();
|
mCodecDownloader = LinphoneCoreFactory.instance().createOpenH264DownloadHelper();
|
||||||
mCodecListener = new OpenH264DownloadHelperListener() {
|
mCodecListener = new OpenH264DownloadHelperListener() {
|
||||||
ProgressDialog progress;
|
ProgressDialog progress;
|
||||||
int box = 1;
|
|
||||||
int ctxt = 0;
|
int ctxt = 0;
|
||||||
|
int box = 1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void OnProgress(final int current, final int max) {
|
public void OnProgress(final int current, final int max) {
|
||||||
|
@ -240,8 +230,10 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
progress.dismiss();
|
progress.dismiss();
|
||||||
progress = null;
|
progress = null;
|
||||||
LinphoneManager.getLc().reloadMsPlugins(null);
|
LinphoneManager.getLc().reloadMsPlugins(null);
|
||||||
if (ohcodec.getUserDataSize() > box && ohcodec.getUserData(box) != null)
|
if (ohcodec.getUserDataSize() > box && ohcodec.getUserData(box) != null) {
|
||||||
((CheckBoxPreference)ohcodec.getUserData(box)).setSummary(mCodecDownloader.getLicenseMessage());
|
((CheckBoxPreference) ohcodec.getUserData(box)).setSummary(mCodecDownloader.getLicenseMessage());
|
||||||
|
((CheckBoxPreference) ohcodec.getUserData(box)).setTitle("OpenH264");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -689,6 +681,32 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initPushNotificationsService() {
|
||||||
|
try {
|
||||||
|
Class<?> GCMRegistrar = Class.forName("com.google.android.gcm.GCMRegistrar");
|
||||||
|
GCMRegistrar.getMethod("checkDevice", Context.class).invoke(null, mServiceContext);
|
||||||
|
try {
|
||||||
|
GCMRegistrar.getMethod("checkManifest", Context.class).invoke(null, mServiceContext);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
Log.e("[Push Notification] No receiver found", e);
|
||||||
|
}
|
||||||
|
final String regId = (String)GCMRegistrar.getMethod("getRegistrationId", Context.class).invoke(null, mServiceContext);
|
||||||
|
String newPushSenderID = mServiceContext.getString(R.string.push_sender_id);
|
||||||
|
String currentPushSenderID = LinphonePreferences.instance().getPushNotificationRegistrationID();
|
||||||
|
if (regId.equals("") || currentPushSenderID == null || !currentPushSenderID.equals(newPushSenderID)) {
|
||||||
|
GCMRegistrar.getMethod("register", Context.class, String[].class).invoke(null, mServiceContext, new String[]{newPushSenderID});
|
||||||
|
Log.i("[Push Notification] Storing current sender id = " + newPushSenderID);
|
||||||
|
} else {
|
||||||
|
Log.i("[Push Notification] Already registered with id = " + regId);
|
||||||
|
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
|
||||||
|
}
|
||||||
|
} catch (java.lang.UnsupportedOperationException e) {
|
||||||
|
Log.i("[Push Notification] Not activated");
|
||||||
|
} catch (Exception e1) {
|
||||||
|
Log.i("[Push Notification] Assuming GCM jar is not provided.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private synchronized void initLiblinphone(LinphoneCore lc) throws LinphoneCoreException {
|
private synchronized void initLiblinphone(LinphoneCore lc) throws LinphoneCoreException {
|
||||||
mLc = lc;
|
mLc = lc;
|
||||||
|
|
||||||
|
@ -742,7 +760,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
mLc.migrateCallLogs();
|
mLc.migrateCallLogs();
|
||||||
|
|
||||||
if (mServiceContext.getResources().getBoolean(R.bool.enable_push_id)) {
|
if (mServiceContext.getResources().getBoolean(R.bool.enable_push_id)) {
|
||||||
Compatibility.initPushNotificationService(mServiceContext);
|
initPushNotificationsService();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1021,6 +1039,15 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAudioManagerInCallMode() {
|
||||||
|
if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
|
||||||
|
Log.w("[AudioManager] already in MODE_IN_COMMUNICATION, skipping...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.d("[AudioManager] Mode: MODE_IN_COMMUNICATION");
|
||||||
|
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("Wakelock")
|
@SuppressLint("Wakelock")
|
||||||
public void callState(final LinphoneCore lc,final LinphoneCall call, final State state, final String message) {
|
public void callState(final LinphoneCore lc,final LinphoneCall call, final State state, final String message) {
|
||||||
Log.i("New call state [",state,"]");
|
Log.i("New call state [",state,"]");
|
||||||
|
@ -1056,7 +1083,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
if (state == State.Connected) {
|
if (state == State.Connected) {
|
||||||
if (mLc.getCallsNb() == 1) {
|
if (mLc.getCallsNb() == 1) {
|
||||||
requestAudioFocus();
|
requestAudioFocus();
|
||||||
Compatibility.setAudioManagerInCallMode(mAudioManager);
|
setAudioManagerInCallMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Hacks.needSoftvolume()) {
|
if (Hacks.needSoftvolume()) {
|
||||||
|
@ -1066,7 +1093,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == State.OutgoingEarlyMedia) {
|
if (state == State.OutgoingEarlyMedia) {
|
||||||
Compatibility.setAudioManagerInCallMode(mAudioManager);
|
setAudioManagerInCallMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == State.CallReleased || state == State.Error) {
|
if (state == State.CallReleased || state == State.Error) {
|
||||||
|
@ -1146,7 +1173,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
|
|
||||||
public void startEcCalibration(LinphoneCoreListener l) throws LinphoneCoreException {
|
public void startEcCalibration(LinphoneCoreListener l) throws LinphoneCoreException {
|
||||||
routeAudioToSpeaker();
|
routeAudioToSpeaker();
|
||||||
Compatibility.setAudioManagerInCallMode((AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE));
|
setAudioManagerInCallMode();
|
||||||
Log.i("Set audio mode on 'Voice Communication'");
|
Log.i("Set audio mode on 'Voice Communication'");
|
||||||
int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
|
int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
|
||||||
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
||||||
|
@ -1155,6 +1182,42 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0);
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int startEchoTester() throws LinphoneCoreException {
|
||||||
|
routeAudioToSpeaker();
|
||||||
|
setAudioManagerInCallMode();
|
||||||
|
Log.i("Set audio mode on 'Voice Communication'");
|
||||||
|
int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
|
||||||
|
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
||||||
|
int sampleRate = 0;
|
||||||
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0);
|
||||||
|
String sampleRateProperty = mAudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
|
||||||
|
sampleRate = Integer.parseInt(sampleRateProperty);
|
||||||
|
int status = mLc.startEchoTester(sampleRate);
|
||||||
|
if (status > 0)
|
||||||
|
echoTesterIsRunning = true;
|
||||||
|
else {
|
||||||
|
echoTesterIsRunning = false;
|
||||||
|
routeAudioToReceiver();
|
||||||
|
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0);
|
||||||
|
((AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE)).setMode(AudioManager.MODE_NORMAL);
|
||||||
|
Log.i("Set audio mode on 'Normal'");
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int stopEchoTester() throws LinphoneCoreException {
|
||||||
|
echoTesterIsRunning = false;
|
||||||
|
int status = mLc.stopEchoTester();
|
||||||
|
routeAudioToReceiver();
|
||||||
|
((AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE)).setMode(AudioManager.MODE_NORMAL);
|
||||||
|
Log.i("Set audio mode on 'Normal'");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getEchoTesterStatus() {
|
||||||
|
return echoTesterIsRunning;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isRinging;
|
private boolean isRinging;
|
||||||
|
|
||||||
private void requestAudioFocus(){
|
private void requestAudioFocus(){
|
||||||
|
@ -1328,88 +1391,6 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
||||||
mAudioManager.adjustStreamVolume(LINPHONE_VOLUME_STREAM, i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
|
mAudioManager.adjustStreamVolume(LINPHONE_VOLUME_STREAM, i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Boolean isProximitySensorNearby(final SensorEvent event) {
|
|
||||||
float threshold = 4.001f; // <= 4 cm is near
|
|
||||||
|
|
||||||
final float distanceInCm = event.values[0];
|
|
||||||
final float maxDistance = event.sensor.getMaximumRange();
|
|
||||||
Log.d("Proximity sensor report [",distanceInCm,"] , for max range [",maxDistance,"]");
|
|
||||||
|
|
||||||
if (maxDistance <= threshold) {
|
|
||||||
// Case binary 0/1 and short sensors
|
|
||||||
threshold = maxDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
return distanceInCm < threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean sLastProximitySensorValueNearby;
|
|
||||||
private static Set<Activity> sProximityDependentActivities = new HashSet<Activity>();
|
|
||||||
private static SensorEventListener sProximitySensorListener = new SensorEventListener() {
|
|
||||||
@Override
|
|
||||||
public void onSensorChanged(SensorEvent event) {
|
|
||||||
if (event.timestamp == 0) return; //just ignoring for nexus 1
|
|
||||||
sLastProximitySensorValueNearby = isProximitySensorNearby(event);
|
|
||||||
proximityNearbyChanged();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
private static void simulateProximitySensorNearby(Activity activity, boolean nearby) {
|
|
||||||
final Window window = activity.getWindow();
|
|
||||||
WindowManager.LayoutParams params = window.getAttributes();
|
|
||||||
View view = ((ViewGroup) window.getDecorView().findViewById(android.R.id.content)).getChildAt(0);
|
|
||||||
if (nearby) {
|
|
||||||
params.screenBrightness = 0.1f;
|
|
||||||
view.setVisibility(View.INVISIBLE);
|
|
||||||
Compatibility.hideNavigationBar(activity);
|
|
||||||
} else {
|
|
||||||
params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
|
|
||||||
view.setVisibility(View.VISIBLE);
|
|
||||||
Compatibility.showNavigationBar(activity);
|
|
||||||
}
|
|
||||||
window.setAttributes(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void proximityNearbyChanged() {
|
|
||||||
boolean nearby = sLastProximitySensorValueNearby;
|
|
||||||
for (Activity activity : sProximityDependentActivities) {
|
|
||||||
simulateProximitySensorNearby(activity, nearby);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void startProximitySensorForActivity(Activity activity) {
|
|
||||||
if (sProximityDependentActivities.contains(activity)) {
|
|
||||||
Log.i("proximity sensor already active for " + activity.getLocalClassName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (sProximityDependentActivities.isEmpty()) {
|
|
||||||
SensorManager sm = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
|
|
||||||
Sensor s = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
|
||||||
if (s != null) {
|
|
||||||
sm.registerListener(sProximitySensorListener,s,SensorManager.SENSOR_DELAY_UI);
|
|
||||||
Log.i("Proximity sensor detected, registering");
|
|
||||||
}
|
|
||||||
} else if (sLastProximitySensorValueNearby){
|
|
||||||
simulateProximitySensorNearby(activity, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
sProximityDependentActivities.add(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void stopProximitySensorForActivity(Activity activity) {
|
|
||||||
sProximityDependentActivities.remove(activity);
|
|
||||||
simulateProximitySensorNearby(activity, false);
|
|
||||||
if (sProximityDependentActivities.isEmpty()) {
|
|
||||||
SensorManager sm = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
|
|
||||||
sm.unregisterListener(sProximitySensorListener);
|
|
||||||
sLastProximitySensorValueNearby = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static synchronized LinphoneCore getLcIfManagerNotDestroyedOrNull() {
|
public static synchronized LinphoneCore getLcIfManagerNotDestroyedOrNull() {
|
||||||
if (sExited || instance == null) {
|
if (sExited || instance == null) {
|
||||||
// Can occur if the UI thread play a posted event but in the meantime the LinphoneManager was destroyed
|
// Can occur if the UI thread play a posted event but in the meantime the LinphoneManager was destroyed
|
||||||
|
|
|
@ -431,7 +431,7 @@ public final class LinphoneUtils {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
p = Runtime.getRuntime().exec(new String[] { "logcat", "-d", "|", "grep", "`adb shell ps | grep org.linphone | cut -c10-15`" });
|
p = Runtime.getRuntime().exec(new String[] { "logcat", "-d", "|", "grep", "`adb shell ps | grep " + context.getPackageName() + " | cut -c10-15`" });
|
||||||
br = new BufferedReader(new InputStreamReader(p.getInputStream()), 2048);
|
br = new BufferedReader(new InputStreamReader(p.getInputStream()), 2048);
|
||||||
|
|
||||||
String line;
|
String line;
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
package org.linphone;
|
|
||||||
|
|
||||||
public class OpenGLESDisplay {
|
|
||||||
public static native void init(int ptr, int width, int height);
|
|
||||||
public static native void render(int ptr);
|
|
||||||
}
|
|
|
@ -48,6 +48,7 @@ import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
|
@ -58,6 +59,7 @@ import android.preference.Preference.OnPreferenceChangeListener;
|
||||||
import android.preference.Preference.OnPreferenceClickListener;
|
import android.preference.Preference.OnPreferenceClickListener;
|
||||||
import android.preference.PreferenceCategory;
|
import android.preference.PreferenceCategory;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Sylvain Berfini
|
* @author Sylvain Berfini
|
||||||
|
@ -611,10 +613,52 @@ public class SettingsFragment extends PreferencesListFragment {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
findPreference(getString(R.string.pref_echo_tester_key)).setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
synchronized (SettingsFragment.this) {
|
||||||
|
int recordAudio = getActivity().getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getActivity().getPackageName());
|
||||||
|
if (recordAudio == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
if (LinphoneManager.getInstance().getEchoTesterStatus())
|
||||||
|
stopEchoTester();
|
||||||
|
else
|
||||||
|
startEchoTester();
|
||||||
|
} else {
|
||||||
|
LinphoneActivity.instance().checkAndRequestRecordAudioPermissionsForEchoTester();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startEchoTester() {
|
||||||
|
Preference preference = findPreference(getString(R.string.pref_echo_tester_key));
|
||||||
|
try {
|
||||||
|
if (LinphoneManager.getInstance().startEchoTester() > 0) {
|
||||||
|
preference.setSummary("Is running");
|
||||||
|
}
|
||||||
|
} catch (LinphoneCoreException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopEchoTester() {
|
||||||
|
Preference preference = findPreference(getString(R.string.pref_echo_tester_key));
|
||||||
|
try {
|
||||||
|
if (LinphoneManager.getInstance().stopEchoTester() > 0) {
|
||||||
|
preference.setSummary("Is stopped");
|
||||||
|
}
|
||||||
|
} catch (LinphoneCoreException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startEchoCancellerCalibration() {
|
public void startEchoCancellerCalibration() {
|
||||||
try {
|
try {
|
||||||
|
if (LinphoneManager.getInstance().getEchoTesterStatus())
|
||||||
|
stopEchoTester();
|
||||||
LinphoneManager.getInstance().startEcCalibration(mListener);
|
LinphoneManager.getInstance().startEcCalibration(mListener);
|
||||||
} catch (LinphoneCoreException e) {
|
} catch (LinphoneCoreException e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
|
@ -642,7 +686,9 @@ public class SettingsFragment extends PreferencesListFragment {
|
||||||
codecs.removeAll();
|
codecs.removeAll();
|
||||||
|
|
||||||
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
||||||
|
|
||||||
final OpenH264DownloadHelper mCodecDownloader = LinphoneManager.getInstance().getOpenH264DownloadHelper();
|
final OpenH264DownloadHelper mCodecDownloader = LinphoneManager.getInstance().getOpenH264DownloadHelper();
|
||||||
|
|
||||||
for (final PayloadType pt : lc.getVideoCodecs()) {
|
for (final PayloadType pt : lc.getVideoCodecs()) {
|
||||||
final CheckBoxPreference codec = new CheckBoxPreference(getActivity());
|
final CheckBoxPreference codec = new CheckBoxPreference(getActivity());
|
||||||
codec.setTitle(pt.getMime());
|
codec.setTitle(pt.getMime());
|
||||||
|
@ -659,8 +705,10 @@ public class SettingsFragment extends PreferencesListFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pt.getMime().equals("H264") && mCodecDownloader.isCodecFound())
|
if (pt.getMime().equals("H264") && mCodecDownloader.isCodecFound()) {
|
||||||
codec.setSummary(mCodecDownloader.getLicenseMessage());
|
codec.setSummary(mCodecDownloader.getLicenseMessage());
|
||||||
|
codec.setTitle("OpenH264");
|
||||||
|
}
|
||||||
codec.setChecked(lc.isPayloadTypeEnabled(pt));
|
codec.setChecked(lc.isPayloadTypeEnabled(pt));
|
||||||
|
|
||||||
codec.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
codec.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
||||||
|
@ -670,9 +718,9 @@ public class SettingsFragment extends PreferencesListFragment {
|
||||||
try {
|
try {
|
||||||
if (enable && Version.getCpuAbis().contains("armeabi-v7a") && !Version.getCpuAbis().contains("x86")
|
if (enable && Version.getCpuAbis().contains("armeabi-v7a") && !Version.getCpuAbis().contains("x86")
|
||||||
&& pt.getMime().equals("H264") && !mCodecDownloader.isCodecFound()) {
|
&& pt.getMime().equals("H264") && !mCodecDownloader.isCodecFound()) {
|
||||||
LinphoneManager.getInstance().getOpenH264DownloadHelper().setOpenH264HelperListener(LinphoneManager.getInstance().getOpenH264HelperListener());
|
mCodecDownloader.setOpenH264HelperListener(LinphoneManager.getInstance().getOpenH264HelperListener());
|
||||||
LinphoneManager.getInstance().getOpenH264DownloadHelper().setUserData(0,LinphoneManager.getInstance().getContext());
|
mCodecDownloader.setUserData(0,LinphoneManager.getInstance().getContext());
|
||||||
LinphoneManager.getInstance().getOpenH264DownloadHelper().setUserData(1,codec);
|
mCodecDownloader.setUserData(1,codec);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(LinphoneManager.getInstance().getContext());
|
AlertDialog.Builder builder = new AlertDialog.Builder(LinphoneManager.getInstance().getContext());
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
|
@ -702,7 +750,6 @@ public class SettingsFragment extends PreferencesListFragment {
|
||||||
|
|
||||||
codecs.addPreference(codec);
|
codecs.addPreference(codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
((CheckBoxPreference) findPreference(getString(R.string.pref_video_enable_key))).setChecked(mPrefs.isVideoEnabled());
|
((CheckBoxPreference) findPreference(getString(R.string.pref_video_enable_key))).setChecked(mPrefs.isVideoEnabled());
|
||||||
((CheckBoxPreference) findPreference(getString(R.string.pref_video_use_front_camera_key))).setChecked(mPrefs.useFrontCam());
|
((CheckBoxPreference) findPreference(getString(R.string.pref_video_use_front_camera_key))).setChecked(mPrefs.useFrontCam());
|
||||||
((CheckBoxPreference) findPreference(getString(R.string.pref_video_initiate_call_with_video_key))).setChecked(mPrefs.shouldInitiateVideoCall());
|
((CheckBoxPreference) findPreference(getString(R.string.pref_video_initiate_call_with_video_key))).setChecked(mPrefs.shouldInitiateVideoCall());
|
||||||
|
@ -1147,6 +1194,24 @@ public class SettingsFragment extends PreferencesListFragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
findPreference(getString(R.string.pref_android_app_settings_key)).setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
synchronized (SettingsFragment.this) {
|
||||||
|
Context context = SettingsFragment.this.getActivity();
|
||||||
|
Intent i = new Intent();
|
||||||
|
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||||
|
i.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
|
i.setData(Uri.parse("package:" + context.getPackageName()));
|
||||||
|
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
|
||||||
|
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||||
|
context.startActivity(i);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
findPreference(getString(R.string.pref_display_name_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
findPreference(getString(R.string.pref_display_name_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
@ -1185,6 +1250,8 @@ public class SettingsFragment extends PreferencesListFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
|
if (LinphoneManager.getInstance().getEchoTesterStatus())
|
||||||
|
stopEchoTester();
|
||||||
LinphoneActivity.instance().hideTopBar();
|
LinphoneActivity.instance().hideTopBar();
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,7 +478,10 @@ public class StatusFragment extends Fragment {
|
||||||
PayloadType payloadAudio = params.getUsedAudioCodec();
|
PayloadType payloadAudio = params.getUsedAudioCodec();
|
||||||
PayloadType payloadVideo = params.getUsedVideoCodec();
|
PayloadType payloadVideo = params.getUsedVideoCodec();
|
||||||
if (payloadVideo != null && payloadAudio != null) {
|
if (payloadVideo != null && payloadAudio != null) {
|
||||||
codec.setText(payloadVideo.getMime() + " / " + payloadAudio.getMime() + (payloadAudio.getRate() / 1000));
|
String videoMime = payloadVideo.getMime();
|
||||||
|
if (payloadVideo.getMime().equals("H264") && LinphoneManager.getInstance().getOpenH264DownloadHelper().isCodecFound())
|
||||||
|
videoMime = "OpenH264";
|
||||||
|
codec.setText(videoMime + " / " + payloadAudio.getMime() + (payloadAudio.getRate() / 1000));
|
||||||
}
|
}
|
||||||
dl.setText(String.valueOf((int) videoStats.getDownloadBandwidth()) + " / " + (int) audioStats.getDownloadBandwidth() + " kbits/s");
|
dl.setText(String.valueOf((int) videoStats.getDownloadBandwidth()) + " / " + (int) audioStats.getDownloadBandwidth() + " kbits/s");
|
||||||
ul.setText(String.valueOf((int) videoStats.getUploadBandwidth()) + " / " + (int) audioStats.getUploadBandwidth() + " kbits/s");
|
ul.setText(String.valueOf((int) videoStats.getUploadBandwidth()) + " / " + (int) audioStats.getUploadBandwidth() + " kbits/s");
|
||||||
|
|
|
@ -19,6 +19,13 @@ along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import org.linphone.LinphoneManager;
|
||||||
|
import org.linphone.R;
|
||||||
|
import org.linphone.core.LinphoneCoreException;
|
||||||
|
import org.linphone.core.OpenH264DownloadHelperListener;
|
||||||
|
import org.linphone.core.PayloadType;
|
||||||
|
import org.linphone.tools.OpenH264DownloadHelper;
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
@ -29,15 +36,6 @@ import android.widget.Button;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.linphone.LinphoneActivity;
|
|
||||||
import org.linphone.LinphoneManager;
|
|
||||||
import org.linphone.R;
|
|
||||||
import org.linphone.core.LinphoneCoreFactory;
|
|
||||||
import org.linphone.core.OpenH264DownloadHelperListener;
|
|
||||||
import org.linphone.core.LinphoneCoreException;
|
|
||||||
import org.linphone.core.PayloadType;
|
|
||||||
import org.linphone.tools.OpenH264DownloadHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Erwan CROZE
|
* @author Erwan CROZE
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -18,11 +18,11 @@ along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
|
import org.linphone.compatibility.Compatibility;
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Html;
|
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -53,7 +53,7 @@ public class LinphoneLoginFragment extends Fragment implements OnClickListener,
|
||||||
password = (EditText) view.findViewById(R.id.assistant_password);
|
password = (EditText) view.findViewById(R.id.assistant_password);
|
||||||
password.addTextChangedListener(this);
|
password.addTextChangedListener(this);
|
||||||
forgotPassword = (TextView) view.findViewById(R.id.forgot_password);
|
forgotPassword = (TextView) view.findViewById(R.id.forgot_password);
|
||||||
forgotPassword.setText(Html.fromHtml("<a href=\"" + url + "\"'>"+ getString(R.string.forgot_password) + "</a>"));
|
forgotPassword.setText(Compatibility.fromHtml("<a href=\"" + url + "\"'>"+ getString(R.string.forgot_password) + "</a>"));
|
||||||
forgotPassword.setMovementMethod(LinkMovementMethod.getInstance());
|
forgotPassword.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
displayName = (EditText) view.findViewById(R.id.assistant_display_name);
|
displayName = (EditText) view.findViewById(R.id.assistant_display_name);
|
||||||
apply = (Button) view.findViewById(R.id.assistant_apply);
|
apply = (Button) view.findViewById(R.id.assistant_apply);
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
package org.linphone.compatibility;
|
|
||||||
|
|
||||||
import org.linphone.LinphonePreferences;
|
|
||||||
import org.linphone.R;
|
|
||||||
import org.linphone.mediastream.Log;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
|
|
||||||
/*
|
|
||||||
ApiEightPlus.java
|
|
||||||
Copyright (C) 2012 Belledonne Communications, Grenoble, France
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation; either version 2
|
|
||||||
of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @author Sylvain Berfini
|
|
||||||
*/
|
|
||||||
|
|
||||||
@TargetApi(8)
|
|
||||||
public class ApiEightPlus {
|
|
||||||
|
|
||||||
public static void initPushNotificationService(Context context) {
|
|
||||||
try {
|
|
||||||
Class<?> GCMRegistrar = Class.forName("com.google.android.gcm.GCMRegistrar");
|
|
||||||
// Starting the push notification service
|
|
||||||
GCMRegistrar.getMethod("checkDevice", Context.class).invoke(null, context);
|
|
||||||
try {
|
|
||||||
GCMRegistrar.getMethod("checkManifest", Context.class).invoke(null, context);
|
|
||||||
} catch (IllegalStateException e){
|
|
||||||
Log.e("Push notification: No receiver found",e);
|
|
||||||
}
|
|
||||||
final String regId = (String)GCMRegistrar.getMethod("getRegistrationId", Context.class).invoke(null, context);
|
|
||||||
String newPushSenderID = context.getString(R.string.push_sender_id);
|
|
||||||
String currentPushSenderID = LinphonePreferences.instance().getPushNotificationRegistrationID();
|
|
||||||
if (regId.equals("") || currentPushSenderID == null || !currentPushSenderID.equals(newPushSenderID)) {
|
|
||||||
GCMRegistrar.getMethod("register", Context.class, String[].class).invoke(null, context, new String[]{newPushSenderID});
|
|
||||||
Log.d("Push Notification: storing current sender id = " + newPushSenderID);
|
|
||||||
} else {
|
|
||||||
Log.d("Push Notification: already registered with id = " + regId);
|
|
||||||
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
|
|
||||||
}
|
|
||||||
} catch (java.lang.UnsupportedOperationException e) {
|
|
||||||
Log.i("Push Notification: not activated");
|
|
||||||
} catch (Exception e1) {
|
|
||||||
//assume the jar is not provided
|
|
||||||
Log.i("Push Notification: assuming GCM jar is not provided.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static String getAudioManagerEventForBluetoothConnectionStateChangedEvent() {
|
|
||||||
return AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,19 +3,15 @@ package org.linphone.compatibility;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.linphone.R;
|
import org.linphone.R;
|
||||||
import org.linphone.mediastream.Log;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.ClipData;
|
|
||||||
import android.content.ClipboardManager;
|
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
|
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
|
||||||
|
@ -120,21 +116,6 @@ public class ApiElevenPlus {
|
||||||
return notif;
|
return notif;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyTextToClipboard(Context context, String msg) {
|
|
||||||
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
|
||||||
ClipData clip = android.content.ClipData.newPlainText("Message", msg);
|
|
||||||
clipboard.setPrimaryClip(clip);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setAudioManagerInCallMode(AudioManager manager) {
|
|
||||||
if (manager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
|
|
||||||
Log.w("---AudioManager: already in MODE_IN_COMMUNICATION, skipping...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Log.d("---AudioManager: set mode to MODE_IN_COMMUNICATION");
|
|
||||||
manager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Intent prepareAddContactIntent(String displayName, String sipUri) {
|
public static Intent prepareAddContactIntent(String displayName, String sipUri) {
|
||||||
Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
|
Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.NAME, displayName);
|
intent.putExtra(ContactsContract.Intents.Insert.NAME, displayName);
|
||||||
|
|
|
@ -1,406 +0,0 @@
|
||||||
package org.linphone.compatibility;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.linphone.LinphoneContact;
|
|
||||||
import org.linphone.R;
|
|
||||||
import org.linphone.core.LinphoneAddress;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.ContentProviderOperation;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.MatrixCursor;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.provider.ContactsContract;
|
|
||||||
import android.provider.ContactsContract.CommonDataKinds;
|
|
||||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
|
||||||
import android.provider.ContactsContract.Contacts;
|
|
||||||
import android.provider.ContactsContract.Data;
|
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
import android.text.ClipboardManager;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.ViewTreeObserver;
|
|
||||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
|
||||||
|
|
||||||
/*
|
|
||||||
ApiFivePlus.java
|
|
||||||
Copyright (C) 2012 Belledonne Communications, Grenoble, France
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation; either version 2
|
|
||||||
of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @author Sylvain Berfini
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@TargetApi(5)
|
|
||||||
public class ApiFivePlus {
|
|
||||||
public static void overridePendingTransition(Activity activity, int idAnimIn, int idAnimOut) {
|
|
||||||
activity.overridePendingTransition(idAnimIn, idAnimOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Intent prepareAddContactIntent(String displayName, String sipUri) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
|
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.NAME, displayName);
|
|
||||||
|
|
||||||
// VoIP field not available, we store the address in the IM field
|
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, sipUri);
|
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.IM_PROTOCOL, "sip");
|
|
||||||
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Intent prepareEditContactIntent(int id) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_EDIT, Contacts.CONTENT_URI);
|
|
||||||
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
|
|
||||||
intent.setData(contactUri);
|
|
||||||
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Intent prepareEditContactIntentWithSipAddress(int id, String sipUri) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_EDIT, Contacts.CONTENT_URI);
|
|
||||||
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
|
|
||||||
intent.setData(contactUri);
|
|
||||||
|
|
||||||
// VoIP field not available, we store the address in the IM field
|
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, sipUri);
|
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.IM_PROTOCOL, "sip");
|
|
||||||
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> extractContactNumbersAndAddresses(String id, ContentResolver cr) {
|
|
||||||
List<String> list = new ArrayList<String>();
|
|
||||||
|
|
||||||
Uri uri = Data.CONTENT_URI;
|
|
||||||
String[] projection = {ContactsContract.CommonDataKinds.Im.DATA};
|
|
||||||
|
|
||||||
// IM addresses
|
|
||||||
String selection = new StringBuilder()
|
|
||||||
.append(Data.CONTACT_ID).append(" = ? AND ")
|
|
||||||
.append(Data.MIMETYPE).append(" = '")
|
|
||||||
.append(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
|
|
||||||
.append("' AND lower(")
|
|
||||||
.append(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL)
|
|
||||||
.append(") = 'sip'")
|
|
||||||
.toString();
|
|
||||||
Cursor c = cr.query(uri, projection, selection, new String[]{id}, null);
|
|
||||||
if (c != null) {
|
|
||||||
int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA);
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
list.add("sip:" + c.getString(nbId));
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phone Numbers
|
|
||||||
c = cr.query(Phone.CONTENT_URI, new String[]{Phone.NUMBER}, Phone.CONTACT_ID + " = " + id, null, null);
|
|
||||||
if (c != null) {
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
String number = c.getString(c.getColumnIndex(Phone.NUMBER));
|
|
||||||
list.add(number);
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getContactsCursor(ContentResolver cr, List<String> ids) {
|
|
||||||
String req = Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL";
|
|
||||||
|
|
||||||
req += " OR (" + Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip')";
|
|
||||||
|
|
||||||
if(ids != null){
|
|
||||||
String s = TextUtils.join(",", ids);
|
|
||||||
req += " OR (" + Data.CONTACT_ID + " IN (" + s + "))";
|
|
||||||
}
|
|
||||||
|
|
||||||
return getGeneralContactCursor(cr, req, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getSIPContactsCursor(ContentResolver cr, List<String> ids) {
|
|
||||||
String req = null;
|
|
||||||
req = Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip'";
|
|
||||||
|
|
||||||
if(ids != null){
|
|
||||||
String s = TextUtils.join(",", ids);
|
|
||||||
req += " OR (" + Data.CONTACT_ID + " IN (" + s + "))";
|
|
||||||
}
|
|
||||||
|
|
||||||
return getGeneralContactCursor(cr, req, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Cursor getSIPContactCursor(ContentResolver cr, String id) {
|
|
||||||
String req = null;
|
|
||||||
req = Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
|
|
||||||
+ " AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip' AND "
|
|
||||||
+ android.provider.ContactsContract.CommonDataKinds.Im.DATA + " LIKE '" + id + "'";
|
|
||||||
|
|
||||||
return getGeneralContactCursor(cr, req, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getGeneralContactCursor(ContentResolver cr, String select, boolean shouldGroupBy) {
|
|
||||||
String[] projection = new String[] { Data.CONTACT_ID, Data.DISPLAY_NAME };
|
|
||||||
String query;
|
|
||||||
|
|
||||||
query = Data.DISPLAY_NAME + " IS NOT NULL AND (" + select + ")";
|
|
||||||
|
|
||||||
Cursor cursor = cr.query(Data.CONTENT_URI, projection, query, null, " lower(" + Data.DISPLAY_NAME + ") COLLATE UNICODE ASC");
|
|
||||||
|
|
||||||
if (!shouldGroupBy || cursor == null) {
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
MatrixCursor result = new MatrixCursor(cursor.getColumnNames());
|
|
||||||
Set<String> groupBy = new HashSet<String>();
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
String name = cursor.getString(getCursorDisplayNameColumnIndex(cursor));
|
|
||||||
if (!groupBy.contains(name)) {
|
|
||||||
groupBy.add(name);
|
|
||||||
Object[] newRow = new Object[cursor.getColumnCount()];
|
|
||||||
|
|
||||||
int contactID = cursor.getColumnIndex(Data.CONTACT_ID);
|
|
||||||
int displayName = cursor.getColumnIndex(Data.DISPLAY_NAME);
|
|
||||||
|
|
||||||
newRow[contactID] = cursor.getString(contactID);
|
|
||||||
newRow[displayName] = cursor.getString(displayName);
|
|
||||||
|
|
||||||
result.addRow(newRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor.close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getCursorDisplayNameColumnIndex(Cursor cursor) {
|
|
||||||
return cursor.getColumnIndex(Data.DISPLAY_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LinphoneContact getContact(ContentResolver cr, Cursor cursor, int position) {
|
|
||||||
try {
|
|
||||||
if(cursor != null) {
|
|
||||||
cursor.moveToFirst();
|
|
||||||
boolean success = cursor.move(position);
|
|
||||||
if (!success)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
String id = cursor.getString(cursor.getColumnIndex(Data.CONTACT_ID));
|
|
||||||
String name = getContactDisplayName(cursor);
|
|
||||||
Uri thumbnail = getContactPictureUri(id);
|
|
||||||
Uri photo = getContactPhotoUri(id);
|
|
||||||
InputStream input = getContactPictureInputStream(cr, id);
|
|
||||||
|
|
||||||
LinphoneContact contact = new LinphoneContact();
|
|
||||||
contact.setAndroidId(id);
|
|
||||||
contact.setFullName(name);
|
|
||||||
if (input != null) {
|
|
||||||
contact.setPhotoUri(photo);
|
|
||||||
contact.setThumbnailUri(thumbnail);
|
|
||||||
}
|
|
||||||
|
|
||||||
return contact;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputStream getContactPictureInputStream(ContentResolver cr, String id) {
|
|
||||||
Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(id));
|
|
||||||
return Contacts.openContactPhotoInputStream(cr, person);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getContactDisplayName(Cursor cursor) {
|
|
||||||
return cursor.getString(cursor.getColumnIndex(Data.DISPLAY_NAME));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Uri getContactPictureUri(String id) {
|
|
||||||
Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(id));
|
|
||||||
return Uri.withAppendedPath(person, Contacts.Photo.CONTENT_DIRECTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Uri getContactPhotoUri(String id) {
|
|
||||||
Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(id));
|
|
||||||
return Uri.withAppendedPath(person, Contacts.Photo.DISPLAY_PHOTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri findUriPictureOfContactAndSetDisplayName(LinphoneAddress address, ContentResolver cr) {
|
|
||||||
String username = address.getUserName();
|
|
||||||
String domain = address.getDomain();
|
|
||||||
String sipUri = username + "@" + domain;
|
|
||||||
|
|
||||||
Cursor cursor = getSIPContactCursor(cr, sipUri);
|
|
||||||
if(cursor != null) {
|
|
||||||
LinphoneContact contact = getContact(cr, cursor, 0);
|
|
||||||
if (contact != null && contact.getNumbersOrAddresses().contains(sipUri)) {
|
|
||||||
address.setDisplayName(contact.getFullName());
|
|
||||||
cursor.close();
|
|
||||||
return contact.getPhotoUri();
|
|
||||||
}
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String refreshContactName(ContentResolver cr, String id) {
|
|
||||||
Cursor cursor = getGeneralContactCursor(cr, Data.CONTACT_ID + " = '" + id + "'", false);
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
String contactDisplayName = getContactDisplayName(cursor);
|
|
||||||
cursor.close();
|
|
||||||
return contactDisplayName;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Notification createMessageNotification(Context context, String title, String msg, PendingIntent intent) {
|
|
||||||
Notification notif = new Notification();
|
|
||||||
notif.icon = R.drawable.topbar_chat_notification;
|
|
||||||
notif.iconLevel = 0;
|
|
||||||
notif.when = System.currentTimeMillis();
|
|
||||||
notif.flags &= Notification.FLAG_ONGOING_EVENT;
|
|
||||||
|
|
||||||
notif.defaults |= Notification.DEFAULT_VIBRATE;
|
|
||||||
notif.defaults |= Notification.DEFAULT_SOUND;
|
|
||||||
notif.defaults |= Notification.DEFAULT_LIGHTS;
|
|
||||||
|
|
||||||
return notif;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Notification createInCallNotification(Context context, String title, String msg, int iconID, PendingIntent intent) {
|
|
||||||
NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context)
|
|
||||||
.setSmallIcon(iconID)
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setContentText(msg)
|
|
||||||
.setContentIntent(intent);
|
|
||||||
|
|
||||||
return notifBuilder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setPreferenceChecked(Preference preference, boolean checked) {
|
|
||||||
((CheckBoxPreference) preference).setChecked(checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPreferenceChecked(Preference preference) {
|
|
||||||
return ((CheckBoxPreference) preference).isChecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copyTextToClipboard(Context context, String msg) {
|
|
||||||
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
|
||||||
clipboard.setText(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress) {
|
|
||||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
||||||
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Im.DATA, sipAddress)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Im.TYPE, ContactsContract.CommonDataKinds.Im.TYPE_CUSTOM)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Im.LABEL, context.getString(R.string.addressbook_label))
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress, String rawContactID) {
|
|
||||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
|
|
||||||
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Im.DATA, sipAddress)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Im.TYPE, ContactsContract.CommonDataKinds.Im.TYPE_CUSTOM)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Im.LABEL, context.getString(R.string.addressbook_label))
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void updateSipAddressForContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String newSipAddress, String contactID) {
|
|
||||||
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
|
|
||||||
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE + "' AND "
|
|
||||||
+ ContactsContract.CommonDataKinds.Im.DATA + "=?";
|
|
||||||
String[] args = new String[] { String.valueOf(contactID), oldSipAddress };
|
|
||||||
|
|
||||||
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withSelection(select, args)
|
|
||||||
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.Im.DATA, newSipAddress)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteSipAddressFromContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String contactID) {
|
|
||||||
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
|
|
||||||
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE + "' AND "
|
|
||||||
+ ContactsContract.CommonDataKinds.Im.DATA + "=?";
|
|
||||||
String[] args = new String[] { String.valueOf(contactID), oldSipAddress };
|
|
||||||
|
|
||||||
ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withSelection(select, args)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, OnGlobalLayoutListener keyboardListener) {
|
|
||||||
viewTreeObserver.removeGlobalOnLayoutListener(keyboardListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setAudioManagerInCallMode(AudioManager manager) {
|
|
||||||
/* Do not use MODE_IN_CALL, because it is reserved to GSM. This is causing conflicts on audio system resulting in silenced audio.*/
|
|
||||||
//manager.setMode(AudioManager.MODE_IN_CALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Notification createNotification(Context context, String title, String message, int icon, int level, PendingIntent intent, boolean isOngoingEvent) {
|
|
||||||
NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context)
|
|
||||||
.setSmallIcon(icon, level)
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setContentText(message)
|
|
||||||
.setContentIntent(intent);
|
|
||||||
|
|
||||||
return notifBuilder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Notification createSimpleNotification(Context context, String title, String text, PendingIntent intent) {
|
|
||||||
NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context)
|
|
||||||
.setSmallIcon(R.drawable.linphone_logo)
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setContentText(text)
|
|
||||||
.setContentIntent(intent);
|
|
||||||
|
|
||||||
Notification notif = notifBuilder.build();
|
|
||||||
notif.defaults |= Notification.DEFAULT_VIBRATE;
|
|
||||||
notif.defaults |= Notification.DEFAULT_SOUND;
|
|
||||||
notif.defaults |= Notification.DEFAULT_LIGHTS;
|
|
||||||
|
|
||||||
return notif;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package org.linphone.compatibility;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.preference.Preference;
|
|
||||||
import android.preference.TwoStatePreference;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
/*
|
|
||||||
ApiFourteenPlus.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @author Sylvain Berfini
|
|
||||||
*/
|
|
||||||
@TargetApi(14)
|
|
||||||
public class ApiFourteenPlus {
|
|
||||||
|
|
||||||
public static void setPreferenceChecked(Preference preference, boolean checked) {
|
|
||||||
((TwoStatePreference) preference).setChecked(checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPreferenceChecked(Preference preference) {
|
|
||||||
return ((TwoStatePreference) preference).isChecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void hideNavigationBar(Activity activity) {
|
|
||||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showNavigationBar(Activity activity) {
|
|
||||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAudioManagerEventForBluetoothConnectionStateChangedEvent() {
|
|
||||||
return AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,195 +0,0 @@
|
||||||
package org.linphone.compatibility;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.LinphoneContact;
|
|
||||||
import org.linphone.R;
|
|
||||||
import org.linphone.core.LinphoneAddress;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.ContentProviderOperation;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.provider.ContactsContract;
|
|
||||||
import android.provider.ContactsContract.CommonDataKinds;
|
|
||||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
|
||||||
import android.provider.ContactsContract.Contacts;
|
|
||||||
import android.provider.ContactsContract.Data;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
/*
|
|
||||||
ApiNinePlus.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @author Sylvain Berfini
|
|
||||||
*/
|
|
||||||
@TargetApi(9)
|
|
||||||
public class ApiNinePlus {
|
|
||||||
|
|
||||||
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress) {
|
|
||||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
||||||
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.SipAddress.DATA, sipAddress)
|
|
||||||
.withValue(CommonDataKinds.SipAddress.TYPE, CommonDataKinds.SipAddress.TYPE_CUSTOM)
|
|
||||||
.withValue(CommonDataKinds.SipAddress.LABEL, context.getString(R.string.addressbook_label))
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress, String rawContactID) {
|
|
||||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
|
|
||||||
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.SipAddress.DATA, sipAddress)
|
|
||||||
.withValue(CommonDataKinds.SipAddress.TYPE, CommonDataKinds.SipAddress.TYPE_CUSTOM)
|
|
||||||
.withValue(CommonDataKinds.SipAddress.LABEL, context.getString(R.string.addressbook_label))
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void updateSipAddressForContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String newSipAddress, String contactID) {
|
|
||||||
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
|
|
||||||
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' AND "
|
|
||||||
+ ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + "=?";
|
|
||||||
String[] args = new String[] { String.valueOf(contactID), oldSipAddress };
|
|
||||||
|
|
||||||
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withSelection(select, args)
|
|
||||||
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS, newSipAddress)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteSipAddressFromContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String contactID) {
|
|
||||||
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
|
|
||||||
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' AND "
|
|
||||||
+ ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + "=? ";
|
|
||||||
String[] args = new String[] { String.valueOf(contactID), oldSipAddress };
|
|
||||||
|
|
||||||
ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
|
|
||||||
.withSelection(select, args)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> extractContactNumbersAndAddresses(String id, ContentResolver cr) {
|
|
||||||
List<String> list = new ArrayList<String>();
|
|
||||||
|
|
||||||
Uri uri = Data.CONTENT_URI;
|
|
||||||
String[] projection;
|
|
||||||
|
|
||||||
// SIP addresses
|
|
||||||
String selection2 = new StringBuilder()
|
|
||||||
.append(Data.CONTACT_ID)
|
|
||||||
.append(" = ? AND ")
|
|
||||||
.append(Data.MIMETYPE)
|
|
||||||
.append(" = '")
|
|
||||||
.append(ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
|
|
||||||
.append("'")
|
|
||||||
.toString();
|
|
||||||
projection = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS};
|
|
||||||
Cursor c = cr.query(uri, projection, selection2, new String[]{id}, null);
|
|
||||||
if (c != null) {
|
|
||||||
int nbid = c.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
list.add("sip:" + c.getString(nbid));
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phone Numbers
|
|
||||||
c = cr.query(Phone.CONTENT_URI, new String[] { Phone.NUMBER }, Phone.CONTACT_ID + " = " + id, null, null);
|
|
||||||
if (c != null) {
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
String number = c.getString(c.getColumnIndex(Phone.NUMBER));
|
|
||||||
list.add(number);
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getContactsCursor(ContentResolver cr, String search, List<String> ids) {
|
|
||||||
String req;
|
|
||||||
if(ids != null && ids.size() > 0) {
|
|
||||||
req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL "
|
|
||||||
+ " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL)"
|
|
||||||
+ " OR (" + Data.CONTACT_ID + " IN (" + TextUtils.join(" , ", ids) + ")))";
|
|
||||||
} else {
|
|
||||||
req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL "
|
|
||||||
+ " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL))";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (search != null) {
|
|
||||||
req += " AND " + Data.DISPLAY_NAME + " LIKE '%" + search + "%'";
|
|
||||||
}
|
|
||||||
|
|
||||||
return ApiFivePlus.getGeneralContactCursor(cr, req, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getSIPContactsCursor(ContentResolver cr, String search, List<String> ids) {
|
|
||||||
|
|
||||||
String req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL) ";
|
|
||||||
|
|
||||||
if(ids != null && ids.size() > 0) {
|
|
||||||
req += " OR (" + Data.CONTACT_ID + " IN (" + TextUtils.join(" , ", ids) + "))";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (search != null) {
|
|
||||||
req += " AND " + Data.DISPLAY_NAME + " LIKE '%" + search + "%'";
|
|
||||||
}
|
|
||||||
|
|
||||||
return ApiFivePlus.getGeneralContactCursor(cr, req, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Cursor getSIPContactCursor(ContentResolver cr, String id) {
|
|
||||||
String req = null;
|
|
||||||
req = Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
|
||||||
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " LIKE '" + id + "'";
|
|
||||||
|
|
||||||
return ApiFivePlus.getGeneralContactCursor(cr, req, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri findUriPictureOfContactAndSetDisplayName(LinphoneAddress address, ContentResolver cr) {
|
|
||||||
String username = address.getUserName();
|
|
||||||
String domain = address.getDomain();
|
|
||||||
String sipUri = username + "@" + domain;
|
|
||||||
|
|
||||||
Cursor cursor = getSIPContactCursor(cr, sipUri);
|
|
||||||
LinphoneContact contact = ApiFivePlus.getContact(cr, cursor, 0);
|
|
||||||
if (contact != null && contact.getNumbersOrAddresses().contains(sipUri)) {
|
|
||||||
address.setDisplayName(contact.getFullName());
|
|
||||||
cursor.close();
|
|
||||||
return contact.getPhotoUri();
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
@TargetApi(16)
|
@TargetApi(16)
|
||||||
public class ApiSixteenPlus {
|
public class ApiSixteenPlus {
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public static Notification createMessageNotification(Context context,
|
public static Notification createMessageNotification(Context context,
|
||||||
int msgCount, String msgSender, String msg, Bitmap contactIcon,
|
int msgCount, String msgSender, String msg, Bitmap contactIcon,
|
||||||
PendingIntent intent) {
|
PendingIntent intent) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
@TargetApi(21)
|
@TargetApi(21)
|
||||||
public class ApiTwentyOnePlus {
|
public class ApiTwentyOnePlus {
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public static Notification createMessageNotification(Context context,
|
public static Notification createMessageNotification(Context context,
|
||||||
int msgCount, String msgSender, String msg, Bitmap contactIcon,
|
int msgCount, String msgSender, String msg, Bitmap contactIcon,
|
||||||
PendingIntent intent) {
|
PendingIntent intent) {
|
||||||
|
|
|
@ -17,191 +17,54 @@ You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.linphone.LinphoneContact;
|
|
||||||
import org.linphone.core.LinphoneAddress;
|
|
||||||
import org.linphone.mediastream.Version;
|
import org.linphone.mediastream.Version;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.ContentProviderOperation;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.preference.Preference;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||||
/**
|
/**
|
||||||
* @author Sylvain Berfini
|
* @author Sylvain Berfini
|
||||||
*/
|
*/
|
||||||
public class Compatibility {
|
public class Compatibility {
|
||||||
public static void overridePendingTransition(Activity activity, int idAnimIn, int idAnimOut) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
|
|
||||||
ApiFivePlus.overridePendingTransition(activity, idAnimIn, idAnimOut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Intent prepareAddContactIntent(String displayName, String sipUri) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
return ApiElevenPlus.prepareAddContactIntent(displayName, sipUri);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.prepareAddContactIntent(displayName, sipUri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Intent prepareEditContactIntent(int id) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
|
|
||||||
return ApiFivePlus.prepareEditContactIntent(id);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Intent prepareEditContactIntentWithSipAddress(int id, String sipAddress) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
return ApiElevenPlus.prepareEditContactIntentWithSipAddress(id, sipAddress);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.prepareEditContactIntent(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> extractContactNumbersAndAddresses(String id, ContentResolver cr) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
return ApiNinePlus.extractContactNumbersAndAddresses(id, cr);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.extractContactNumbersAndAddresses(id, cr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> extractContactImAddresses(String id, ContentResolver cr) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
return ApiFivePlus.extractContactNumbersAndAddresses(id, cr);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getContactsCursor(ContentResolver cr, List<String> contactsId) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
return ApiNinePlus.getContactsCursor(cr, null, contactsId);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.getContactsCursor(cr, contactsId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getContactsCursor(ContentResolver cr, String search, List<String> contactsId) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
return ApiNinePlus.getContactsCursor(cr, search, contactsId);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.getContactsCursor(cr, contactsId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getSIPContactsCursor(ContentResolver cr, List<String> contactsId) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
return ApiNinePlus.getSIPContactsCursor(cr, null, contactsId);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.getSIPContactsCursor(cr, contactsId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getSIPContactsCursor(ContentResolver cr, String search, List<String> contactsId) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
return ApiNinePlus.getSIPContactsCursor(cr, search, contactsId);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.getSIPContactsCursor(cr, contactsId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cursor getImContactsCursor(ContentResolver cr) {
|
|
||||||
return ApiFivePlus.getSIPContactsCursor(cr,null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getCursorDisplayNameColumnIndex(Cursor cursor) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
|
|
||||||
return ApiFivePlus.getCursorDisplayNameColumnIndex(cursor);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LinphoneContact getContact(ContentResolver cr, Cursor cursor, int position) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
|
|
||||||
return ApiFivePlus.getContact(cr, cursor, position);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputStream getContactPictureInputStream(ContentResolver cr, String id) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
|
|
||||||
return ApiFivePlus.getContactPictureInputStream(cr, id);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri findUriPictureOfContactAndSetDisplayName(LinphoneAddress address, ContentResolver cr) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
return ApiNinePlus.findUriPictureOfContactAndSetDisplayName(address, cr);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.findUriPictureOfContactAndSetDisplayName(address, cr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Notification createSimpleNotification(Context context, String title, String text, PendingIntent intent) {
|
public static Notification createSimpleNotification(Context context, String title, String text, PendingIntent intent) {
|
||||||
Notification notif = null;
|
Notification notif = null;
|
||||||
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
||||||
return ApiTwentyOnePlus.createSimpleNotification(context, title, text, intent);
|
return ApiTwentyOnePlus.createSimpleNotification(context, title, text, intent);
|
||||||
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||||
notif = ApiSixteenPlus.createSimpleNotification(context, title, text, intent);
|
notif = ApiSixteenPlus.createSimpleNotification(context, title, text, intent);
|
||||||
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
notif = ApiElevenPlus.createSimpleNotification(context, title, text, intent);
|
|
||||||
} else {
|
} else {
|
||||||
notif = ApiFivePlus.createSimpleNotification(context, title, text, intent);
|
notif = ApiElevenPlus.createSimpleNotification(context, title, text, intent);
|
||||||
}
|
}
|
||||||
return notif;
|
return notif;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Notification createMessageNotification(Context context, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
|
public static Notification createMessageNotification(Context context, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
|
||||||
Notification notif = null;
|
Notification notif = null;
|
||||||
String title;
|
|
||||||
if (msgCount == 1) {
|
|
||||||
title = "Unread message from %s".replace("%s", msgSender);
|
|
||||||
} else {
|
|
||||||
title = "%i unread messages".replace("%i", String.valueOf(msgCount));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
||||||
return ApiTwentyOnePlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
|
return ApiTwentyOnePlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
|
||||||
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||||
notif = ApiSixteenPlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
|
notif = ApiSixteenPlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
|
||||||
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
notif = ApiElevenPlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
|
|
||||||
} else {
|
} else {
|
||||||
notif = ApiFivePlus.createMessageNotification(context, title, msg, intent);
|
notif = ApiElevenPlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
|
||||||
}
|
}
|
||||||
return notif;
|
return notif;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Notification createInCallNotification(Context context, String title, String msg, int iconID, Bitmap contactIcon, String contactName, PendingIntent intent) {
|
public static Notification createInCallNotification(Context context, String title, String msg, int iconID, Bitmap contactIcon, String contactName, PendingIntent intent) {
|
||||||
Notification notif = null;
|
Notification notif = null;
|
||||||
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
||||||
return ApiTwentyOnePlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
|
return ApiTwentyOnePlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
|
||||||
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||||
notif = ApiSixteenPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
|
notif = ApiSixteenPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
|
||||||
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
notif = ApiElevenPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
|
|
||||||
} else {
|
} else {
|
||||||
notif = ApiFivePlus.createInCallNotification(context, title, msg, iconID, intent);
|
notif = ApiElevenPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
|
||||||
}
|
}
|
||||||
return notif;
|
return notif;
|
||||||
}
|
}
|
||||||
|
@ -211,20 +74,11 @@ public class Compatibility {
|
||||||
return ApiTwentyOnePlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent,priority);
|
return ApiTwentyOnePlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent,priority);
|
||||||
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||||
return ApiSixteenPlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent,priority);
|
return ApiSixteenPlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent,priority);
|
||||||
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
return ApiElevenPlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent);
|
|
||||||
} else {
|
} else {
|
||||||
return ApiFivePlus.createNotification(context, title, message, icon, iconLevel, intent, isOngoingEvent);
|
return ApiElevenPlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String refreshContactName(ContentResolver cr, String id) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
|
|
||||||
return ApiFivePlus.refreshContactName(cr, id);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CompatibilityScaleGestureDetector getScaleGestureDetector(Context context, CompatibilityScaleGestureListener listener) {
|
public static CompatibilityScaleGestureDetector getScaleGestureDetector(Context context, CompatibilityScaleGestureListener listener) {
|
||||||
if (Version.sdkAboveOrEqual(Version.API08_FROYO_22)) {
|
if (Version.sdkAboveOrEqual(Version.API08_FROYO_22)) {
|
||||||
CompatibilityScaleGestureDetector csgd = new CompatibilityScaleGestureDetector(context);
|
CompatibilityScaleGestureDetector csgd = new CompatibilityScaleGestureDetector(context);
|
||||||
|
@ -234,108 +88,12 @@ public class Compatibility {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public static void setPreferenceChecked(Preference preference, boolean checked) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
|
|
||||||
ApiFourteenPlus.setPreferenceChecked(preference, checked);
|
|
||||||
} else {
|
|
||||||
ApiFivePlus.setPreferenceChecked(preference, checked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPreferenceChecked(Preference preference) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
|
|
||||||
return ApiFourteenPlus.isPreferenceChecked(preference);
|
|
||||||
} else {
|
|
||||||
return ApiFivePlus.isPreferenceChecked(preference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void initPushNotificationService(Context context) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API08_FROYO_22)) {
|
|
||||||
ApiEightPlus.initPushNotificationService(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copyTextToClipboard(Context context, String msg) {
|
|
||||||
if(Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
ApiElevenPlus.copyTextToClipboard(context, msg);
|
|
||||||
} else {
|
|
||||||
ApiFivePlus.copyTextToClipboard(context, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
ApiNinePlus.addSipAddressToContact(context, ops, sipAddress);
|
|
||||||
} else {
|
|
||||||
ApiFivePlus.addSipAddressToContact(context, ops, sipAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress, String rawContactID) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
ApiNinePlus.addSipAddressToContact(context, ops, sipAddress, rawContactID);
|
|
||||||
} else {
|
|
||||||
ApiFivePlus.addSipAddressToContact(context, ops, sipAddress, rawContactID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void updateSipAddressForContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String newSipAddress, String contactID) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
ApiNinePlus.updateSipAddressForContact(ops, oldSipAddress, newSipAddress, contactID);
|
|
||||||
} else {
|
|
||||||
ApiFivePlus.updateSipAddressForContact(ops, oldSipAddress, newSipAddress, contactID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteSipAddressFromContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String contactID) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
|
||||||
ApiNinePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
|
|
||||||
} else {
|
|
||||||
ApiFivePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteImAddressFromContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String contactID) {
|
|
||||||
ApiFivePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, OnGlobalLayoutListener keyboardListener) {
|
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, OnGlobalLayoutListener keyboardListener) {
|
||||||
if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||||
ApiSixteenPlus.removeGlobalLayoutListener(viewTreeObserver, keyboardListener);
|
ApiSixteenPlus.removeGlobalLayoutListener(viewTreeObserver, keyboardListener);
|
||||||
} else {
|
} else {
|
||||||
ApiFivePlus.removeGlobalLayoutListener(viewTreeObserver, keyboardListener);
|
viewTreeObserver.removeGlobalOnLayoutListener(keyboardListener);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void hideNavigationBar(Activity activity)
|
|
||||||
{
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
|
|
||||||
ApiFourteenPlus.hideNavigationBar(activity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showNavigationBar(Activity activity)
|
|
||||||
{
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
|
|
||||||
ApiFourteenPlus.showNavigationBar(activity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setAudioManagerInCallMode(AudioManager manager) {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
|
||||||
ApiElevenPlus.setAudioManagerInCallMode(manager);
|
|
||||||
} else {
|
|
||||||
ApiFivePlus.setAudioManagerInCallMode(manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAudioManagerEventForBluetoothConnectionStateChangedEvent() {
|
|
||||||
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
|
|
||||||
return ApiFourteenPlus.getAudioManagerEventForBluetoothConnectionStateChangedEvent();
|
|
||||||
} else {
|
|
||||||
return ApiEightPlus.getAudioManagerEventForBluetoothConnectionStateChangedEvent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,4 +112,12 @@ public class Compatibility {
|
||||||
return pm.isScreenOn();
|
return pm.isScreenOn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static Spanned fromHtml(String text) {
|
||||||
|
/*if (Version.sdkAboveOrEqual(Version.API24_NOUGAT_70)) {
|
||||||
|
return Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY);
|
||||||
|
}*/
|
||||||
|
return Html.fromHtml(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,13 +53,13 @@ public class GCMService extends GCMBaseIntentService {
|
||||||
@Override
|
@Override
|
||||||
protected void onError(Context context, String errorId) {
|
protected void onError(Context context, String errorId) {
|
||||||
initLogger(context);
|
initLogger(context);
|
||||||
Log.e("Error while registering push notification : " + errorId);
|
Log.e("[Push Notification] Error while registering: " + errorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMessage(Context context, Intent intent) {
|
protected void onMessage(Context context, Intent intent) {
|
||||||
initLogger(context);
|
initLogger(context);
|
||||||
Log.d("Push notification received");
|
Log.d("[Push Notification] Received");
|
||||||
|
|
||||||
if (!LinphoneService.isReady()) {
|
if (!LinphoneService.isReady()) {
|
||||||
startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
|
startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
|
||||||
|
@ -79,7 +79,7 @@ public class GCMService extends GCMBaseIntentService {
|
||||||
@Override
|
@Override
|
||||||
protected void onRegistered(Context context, String regId) {
|
protected void onRegistered(Context context, String regId) {
|
||||||
initLogger(context);
|
initLogger(context);
|
||||||
Log.d("Registered push notification : " + regId);
|
Log.d("[Push Notification] Registered: " + regId);
|
||||||
|
|
||||||
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
|
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ public class GCMService extends GCMBaseIntentService {
|
||||||
@Override
|
@Override
|
||||||
protected void onUnregistered(Context context, String regId) {
|
protected void onUnregistered(Context context, String regId) {
|
||||||
initLogger(context);
|
initLogger(context);
|
||||||
Log.w("Unregistered push notification : " + regId);
|
Log.w("[Push Notification] Unregistered: " + regId);
|
||||||
|
|
||||||
LinphonePreferences.instance().setPushNotificationRegistrationID(null);
|
LinphonePreferences.instance().setPushNotificationRegistrationID(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,8 +162,7 @@ public class TutorialCardDavSync extends Activity implements OnClickListener, Li
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinphoneFriendSyncStatusChanged(LinphoneFriendList list,
|
public void onLinphoneFriendSyncStatusChanged(LinphoneFriendList list, LinphoneFriendList.State status, String message) {
|
||||||
org.linphone.core.LinphoneFriendList.State status, String message) {
|
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
String msg = "Sync status changed: " + status.toString() + " (" + message + ")";
|
String msg = "Sync status changed: " + status.toString() + " (" + message + ")";
|
||||||
myLog(msg);
|
myLog(msg);
|
||||||
|
|
|
@ -1,463 +0,0 @@
|
||||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import org.linphone.LinphoneActivity;
|
|
||||||
import org.linphone.LinphoneContact;
|
|
||||||
import org.linphone.LinphoneManager;
|
|
||||||
import org.linphone.LinphoneUtils;
|
|
||||||
import org.linphone.R;
|
|
||||||
import org.linphone.core.LinphoneBuffer;
|
|
||||||
import org.linphone.core.LinphoneChatMessage;
|
|
||||||
import org.linphone.core.LinphoneChatMessage.State;
|
|
||||||
import org.linphone.core.LinphoneContent;
|
|
||||||
import org.linphone.mediastream.Log;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.media.ThumbnailUtils;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.text.Spannable;
|
|
||||||
import android.text.SpannableStringBuilder;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.text.style.ImageSpan;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sylvain Berfini
|
|
||||||
*/
|
|
||||||
@SuppressLint("SimpleDateFormat")
|
|
||||||
public class BubbleChat implements LinphoneChatMessage.LinphoneChatMessageListener {
|
|
||||||
private static final HashMap<String, Integer> emoticons = new HashMap<String, Integer>();
|
|
||||||
|
|
||||||
private View view;
|
|
||||||
private ImageView statusView, contactPicture;
|
|
||||||
private LinphoneChatMessage nativeMessage;
|
|
||||||
private Context mContext;
|
|
||||||
private Button cancelUpload, acceptDownload;
|
|
||||||
private static final int SIZE_MAX = 512;
|
|
||||||
private ProgressBar progressBar, inprogress;
|
|
||||||
private Bitmap defaultBitmap;
|
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
|
||||||
public BubbleChat(final Context context, LinphoneChatMessage message, LinphoneContact c) {
|
|
||||||
if (message == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nativeMessage = message;
|
|
||||||
mContext = context;
|
|
||||||
|
|
||||||
if (message.isOutgoing()) {
|
|
||||||
view = LayoutInflater.from(context).inflate(R.layout.chat_bubble_outgoing, null);
|
|
||||||
} else {
|
|
||||||
view = LayoutInflater.from(context).inflate(R.layout.chat_bubble_incoming, null);
|
|
||||||
}
|
|
||||||
view.setId(message.getStorageId());
|
|
||||||
|
|
||||||
defaultBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chat_picture_over);
|
|
||||||
inprogress = (ProgressBar) view.findViewById(R.id.inprogress);
|
|
||||||
progressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
|
|
||||||
|
|
||||||
LinphoneChatMessage.State status = message.getStatus();
|
|
||||||
statusView = (ImageView) view.findViewById(R.id.status);
|
|
||||||
|
|
||||||
if (statusView != null) {
|
|
||||||
if (status == LinphoneChatMessage.State.Delivered) {
|
|
||||||
statusView.setVisibility(View.INVISIBLE);
|
|
||||||
inprogress.setVisibility(View.GONE);
|
|
||||||
} else if (status == LinphoneChatMessage.State.NotDelivered) {
|
|
||||||
statusView.setVisibility(View.VISIBLE);
|
|
||||||
statusView.setImageResource(R.drawable.chat_message_not_delivered);
|
|
||||||
} else {
|
|
||||||
statusView.setVisibility(View.GONE);
|
|
||||||
inprogress.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String externalBodyUrl = message.getExternalBodyUrl();
|
|
||||||
LinphoneContent fileTransferContent = message.getFileTransferInformation();
|
|
||||||
|
|
||||||
if(nativeMessage.isOutgoing()){
|
|
||||||
cancelUpload = (Button) view.findViewById(R.id.cancel_upload);
|
|
||||||
cancelUpload.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (LinphoneManager.getInstance().getMessageUploadPending() != null) {
|
|
||||||
progressBar.setVisibility(View.GONE);
|
|
||||||
progressBar.setProgress(0);
|
|
||||||
nativeMessage.cancelFileTransfer();
|
|
||||||
LinphoneManager.getInstance().setUploadPendingFileMessage(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(LinphoneManager.getInstance().getMessageUploadPending() != null){
|
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
|
||||||
LinphoneManager.addListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (externalBodyUrl != null || fileTransferContent != null) {
|
|
||||||
String appData = message.getAppData();
|
|
||||||
ImageView imageView = (ImageView) view.findViewById(R.id.image);
|
|
||||||
|
|
||||||
if(nativeMessage.isOutgoing() && appData != null){
|
|
||||||
imageView.setVisibility(View.VISIBLE);
|
|
||||||
loadBitmap(appData, imageView);
|
|
||||||
|
|
||||||
RelativeLayout imageLayout = (RelativeLayout) view.findViewById(R.id.file_transfer_layout);
|
|
||||||
if(LinphoneManager.getInstance().getMessageUploadPending() != null && LinphoneManager.getInstance().getMessageUploadPending().getStorageId() == nativeMessage.getStorageId()){
|
|
||||||
inprogress.setVisibility(View.INVISIBLE);
|
|
||||||
imageLayout.setVisibility(View.VISIBLE);
|
|
||||||
nativeMessage.setListener(LinphoneManager.getInstance());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (appData != null && !LinphoneManager.getInstance().isMessagePending(nativeMessage) &&
|
|
||||||
appData.contains(context.getString(R.string.temp_photo_name_with_date).split("%s")[0])) {
|
|
||||||
appData = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
RelativeLayout imageLayout = (RelativeLayout) view.findViewById(R.id.file_transfer_layout);
|
|
||||||
acceptDownload = (Button) view.findViewById(R.id.accept_download);
|
|
||||||
|
|
||||||
if (appData == null) {
|
|
||||||
LinphoneManager.addListener(this);
|
|
||||||
imageLayout.setVisibility(View.VISIBLE);
|
|
||||||
acceptDownload.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (mContext.getPackageManager().checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, mContext.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
v.setEnabled(false);
|
|
||||||
String extension = nativeMessage.getFileTransferInformation().getSubtype();
|
|
||||||
String filename = context.getString(R.string.temp_photo_name_with_date).replace("%s", String.valueOf(System.currentTimeMillis())) + "." + extension;
|
|
||||||
File file = new File(Environment.getExternalStorageDirectory(), filename);
|
|
||||||
nativeMessage.setAppData(filename);
|
|
||||||
LinphoneManager.getInstance().addDownloadMessagePending(nativeMessage);
|
|
||||||
nativeMessage.setListener(LinphoneManager.getInstance());
|
|
||||||
nativeMessage.setFileTransferFilepath(file.getPath());
|
|
||||||
nativeMessage.downloadFile();
|
|
||||||
} else {
|
|
||||||
Log.w("WRITE_EXTERNAL_STORAGE permission not granted, won't be able to store the downloaded file");
|
|
||||||
LinphoneActivity.instance().checkAndRequestExternalStoragePermission();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (LinphoneManager.getInstance().isMessagePending(nativeMessage)) {
|
|
||||||
LinphoneManager.addListener(this);
|
|
||||||
acceptDownload.setEnabled(false);
|
|
||||||
imageLayout.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
LinphoneManager.removeListener(this);
|
|
||||||
imageLayout.setVisibility(View.GONE);
|
|
||||||
imageView.setVisibility(View.VISIBLE);
|
|
||||||
loadBitmap(appData, imageView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
TextView msgView = (TextView) view.findViewById(R.id.message);
|
|
||||||
if (msgView != null) {
|
|
||||||
Spanned text = null;
|
|
||||||
String msg = message.getText();
|
|
||||||
if (msg != null) {
|
|
||||||
text = getSmiledText(context, getTextWithHttpLinks(msg));
|
|
||||||
msgView.setText(text);
|
|
||||||
msgView.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
msgView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView contact = (TextView) view.findViewById(R.id.contact_header);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
contactPicture = (ImageView) view.findViewById(R.id.contact_picture);
|
|
||||||
|
|
||||||
String displayName = nativeMessage.getFrom().getUserName();
|
|
||||||
if(!nativeMessage.isOutgoing()) {
|
|
||||||
if (c != null) {
|
|
||||||
displayName = c.getFullName();
|
|
||||||
LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture, c.getPhotoUri(), c.getThumbnailUri());
|
|
||||||
} else {
|
|
||||||
contactPicture.setImageResource(R.drawable.avatar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contact.setText(timestampToHumanDate(context, message.getTime()) + " - " + displayName);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getView() {
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
defaultBitmap.recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String timestampToHumanDate(Context context, long timestamp) {
|
|
||||||
try {
|
|
||||||
Calendar cal = Calendar.getInstance();
|
|
||||||
cal.setTimeInMillis(timestamp);
|
|
||||||
|
|
||||||
SimpleDateFormat dateFormat;
|
|
||||||
if (isToday(cal)) {
|
|
||||||
dateFormat = new SimpleDateFormat(context.getResources().getString(R.string.today_date_format));
|
|
||||||
} else {
|
|
||||||
dateFormat = new SimpleDateFormat(context.getResources().getString(R.string.messages_date_format));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dateFormat.format(cal.getTime());
|
|
||||||
} catch (NumberFormatException nfe) {
|
|
||||||
return String.valueOf(timestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isToday(Calendar cal) {
|
|
||||||
return isSameDay(cal, Calendar.getInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isSameDay(Calendar cal1, Calendar cal2) {
|
|
||||||
if (cal1 == null || cal2 == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
|
|
||||||
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
|
|
||||||
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Spannable getSmiledText(Context context, Spanned spanned) {
|
|
||||||
SpannableStringBuilder builder = new SpannableStringBuilder(spanned);
|
|
||||||
String text = spanned.toString();
|
|
||||||
|
|
||||||
for (Entry<String, Integer> entry : emoticons.entrySet()) {
|
|
||||||
String key = entry.getKey();
|
|
||||||
int indexOf = text.indexOf(key);
|
|
||||||
while (indexOf >= 0) {
|
|
||||||
int end = indexOf + key.length();
|
|
||||||
builder.setSpan(new ImageSpan(context, entry.getValue()), indexOf, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
indexOf = text.indexOf(key, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Spanned getTextWithHttpLinks(String text) {
|
|
||||||
if (text.contains("<")) {
|
|
||||||
text = text.replace("<", "<");
|
|
||||||
}
|
|
||||||
if (text.contains(">")) {
|
|
||||||
text = text.replace(">", ">");
|
|
||||||
}
|
|
||||||
if (text.contains("http://")) {
|
|
||||||
int indexHttp = text.indexOf("http://");
|
|
||||||
int indexFinHttp = text.indexOf(" ", indexHttp) == -1 ? text.length() : text.indexOf(" ", indexHttp);
|
|
||||||
String link = text.substring(indexHttp, indexFinHttp);
|
|
||||||
String linkWithoutScheme = link.replace("http://", "");
|
|
||||||
text = text.replaceFirst(link, "<a href=\"" + link + "\">" + linkWithoutScheme + "</a>");
|
|
||||||
}
|
|
||||||
if (text.contains("https://")) {
|
|
||||||
int indexHttp = text.indexOf("https://");
|
|
||||||
int indexFinHttp = text.indexOf(" ", indexHttp) == -1 ? text.length() : text.indexOf(" ", indexHttp);
|
|
||||||
String link = text.substring(indexHttp, indexFinHttp);
|
|
||||||
String linkWithoutScheme = link.replace("https://", "");
|
|
||||||
text = text.replaceFirst(link, "<a href=\"" + link + "\">" + linkWithoutScheme + "</a>");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Html.fromHtml(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTextMessage() {
|
|
||||||
return nativeMessage.getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public State getStatus() {
|
|
||||||
return nativeMessage.getStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LinphoneChatMessage getNativeMessageObject() {
|
|
||||||
return nativeMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getId() {
|
|
||||||
return nativeMessage.getStorageId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadBitmap(String path, ImageView imageView) {
|
|
||||||
if (cancelPotentialWork(path, imageView)) {
|
|
||||||
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
|
|
||||||
final AsyncBitmap asyncBitmap = new AsyncBitmap(mContext.getResources(), defaultBitmap, task);
|
|
||||||
imageView.setImageDrawable(asyncBitmap);
|
|
||||||
task.execute(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
|
|
||||||
private final WeakReference<ImageView> imageViewReference;
|
|
||||||
public String path;
|
|
||||||
|
|
||||||
public BitmapWorkerTask(ImageView imageView) {
|
|
||||||
path = null;
|
|
||||||
// Use a WeakReference to ensure the ImageView can be garbage collected
|
|
||||||
imageViewReference = new WeakReference<ImageView>(imageView);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode image in background.
|
|
||||||
@Override
|
|
||||||
protected Bitmap doInBackground(String... params) {
|
|
||||||
path = params[0];
|
|
||||||
Bitmap bm = null;
|
|
||||||
|
|
||||||
if (path.startsWith("content")) {
|
|
||||||
try {
|
|
||||||
bm = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), Uri.parse(path));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Log.e(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bm = BitmapFactory.decodeFile(path);
|
|
||||||
path = "file://" + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bm != null) {
|
|
||||||
bm = ThumbnailUtils.extractThumbnail(bm, SIZE_MAX, SIZE_MAX);
|
|
||||||
}
|
|
||||||
return bm;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Once complete, see if ImageView is still around and set bitmap.
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Bitmap bitmap) {
|
|
||||||
if (isCancelled()) {
|
|
||||||
bitmap = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imageViewReference != null && bitmap != null) {
|
|
||||||
final ImageView imageView = imageViewReference.get();
|
|
||||||
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
|
|
||||||
if (this == bitmapWorkerTask && imageView != null) {
|
|
||||||
imageView.setImageBitmap(bitmap);
|
|
||||||
imageView.setTag(path);
|
|
||||||
imageView.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
||||||
intent.setDataAndType(Uri.parse((String)v.getTag()), "image/*");
|
|
||||||
mContext.startActivity(intent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class AsyncBitmap extends BitmapDrawable {
|
|
||||||
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
|
|
||||||
|
|
||||||
public AsyncBitmap(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
|
|
||||||
super(res, bitmap);
|
|
||||||
bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BitmapWorkerTask getBitmapWorkerTask() {
|
|
||||||
return bitmapWorkerTaskReference.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean cancelPotentialWork(String path, ImageView imageView) {
|
|
||||||
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
|
|
||||||
|
|
||||||
if (bitmapWorkerTask != null) {
|
|
||||||
final String bitmapData = bitmapWorkerTask.path;
|
|
||||||
// If bitmapData is not yet set or it differs from the new data
|
|
||||||
if (bitmapData == null || bitmapData != path) {
|
|
||||||
// Cancel previous task
|
|
||||||
bitmapWorkerTask.cancel(true);
|
|
||||||
} else {
|
|
||||||
// The same work is already in progress
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// No task associated with the ImageView, or an existing task was cancelled
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
|
|
||||||
if (imageView != null) {
|
|
||||||
final Drawable drawable = imageView.getDrawable();
|
|
||||||
if (drawable instanceof AsyncBitmap) {
|
|
||||||
final AsyncBitmap asyncDrawable = (AsyncBitmap) drawable;
|
|
||||||
return asyncDrawable.getBitmapWorkerTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinphoneChatMessageFileTransferSent(LinphoneChatMessage msg, LinphoneContent content, int offset, int size, LinphoneBuffer bufferToFill) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinphoneChatMessageFileTransferProgressChanged(LinphoneChatMessage msg, LinphoneContent content, int offset, int total) {
|
|
||||||
if(nativeMessage.getStorageId() == msg.getStorageId())
|
|
||||||
progressBar.setProgress(offset * 100 / total);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit fbac73d6704f9f5697770188747639e519a28819
|
Subproject commit 921a21332c327ae99900267950be0bfd2d7c6126
|
|
@ -1 +1 @@
|
||||||
Subproject commit 086bb16bd79180265136ed9d4a89661049c95016
|
Subproject commit b553f58c3f23633b9c183af5784b2170b6b4aa91
|
|
@ -1 +1 @@
|
||||||
Subproject commit 29911ee5ba6053dd041ee02c6dc13b0134e890d2
|
Subproject commit f4eac4803eee43de3efa96ecca9450ba4f2bc7dc
|
|
@ -1 +1 @@
|
||||||
Subproject commit 61a3b8a98e6d35bff351b64e2c6717491792afb3
|
Subproject commit 958366ce1928bd0aabaf983082faa8c49e501c4a
|
|
@ -40,7 +40,7 @@
|
||||||
</condition>
|
</condition>
|
||||||
<exec executable="bash" unless:set="has.crashed">
|
<exec executable="bash" unless:set="has.crashed">
|
||||||
<arg value="-c"/>
|
<arg value="-c"/>
|
||||||
<arg value="adb shell run-as org.linphone cat /data/data/org.linphone/files/junit-report.xml > linphone-junit-report-${test.size}.xml"/>
|
<arg value="adb shell cat /data/data/org.linphone/files/junit-report.xml > linphone-junit-report-${test.size}.xml"/>
|
||||||
</exec>
|
</exec>
|
||||||
|
|
||||||
<zip destfile="${archive.name}.zip">
|
<zip destfile="${archive.name}.zip">
|
||||||
|
|
Loading…
Reference in a new issue