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:
|
||||
-------------------------------------------
|
||||
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.
|
||||
1) download the Android ndk (version r11) from google and add it to your path (no symlink !!!).
|
||||
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 r11c or 12b) from google and add it to your path (no symlink !!!).
|
||||
2) install yasm, nasm, ant, python, cmake and vim-common
|
||||
On 64 bits linux systems you'll need the ia32-libs package
|
||||
With the latest Debian (multiarch), you need this:
|
||||
|
@ -27,11 +27,12 @@ To build liblinphone for Android, you must:
|
|||
$ make mediastreamer2-sdk
|
||||
8) (Optional) To generate a signed apk to publish on the Google Play, run
|
||||
$ 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.
|
||||
You also may want to create a file name ant_password.properties with the following:
|
||||
key.store.password=[your_password]
|
||||
key.alias.password=[your_password]
|
||||
If you don't, the passwords will be asked at the signing phase.
|
||||
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:
|
||||
key.store.password=[your_password]
|
||||
key.alias.password=[your_password]
|
||||
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:
|
||||
--------------------
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
</condition>
|
||||
<exec executable="bash" unless:set="has.crashed">
|
||||
<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>
|
||||
|
||||
<zip destfile="${archive.name}.zip">
|
||||
|
|
|
@ -128,8 +128,9 @@
|
|||
<ListView
|
||||
android:id="@+id/chat_message_list"
|
||||
android:divider="@android:color/transparent"
|
||||
android:choiceMode="multipleChoice"
|
||||
android:stackFromBottom="true"
|
||||
android:transcriptMode="alwaysScroll"
|
||||
android:transcriptMode="normal"
|
||||
android:dividerHeight="10dp"
|
||||
android:cacheColorHint="@color/transparent"
|
||||
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"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/contactOrganizationTitle"
|
||||
android:text="@string/contact_organization"
|
||||
style="@style/font13"
|
||||
android:textAllCaps="true"
|
||||
|
|
|
@ -71,6 +71,8 @@
|
|||
<bool name="allow_only_one_phone_number">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="enable_call_notification">true</bool>
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
<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_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_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_device_ringtone_key">pref_device_ringtone_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>
|
||||
|
|
|
@ -273,6 +273,7 @@
|
|||
<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_canceller_calibration">Echo canceler calibration</string>
|
||||
<string name="pref_echo_tester">Test echo</string>
|
||||
<string name="ec_calibrating">Calibrating…</string>
|
||||
<string name="ec_calibrated">Calibrated in %s ms</string>
|
||||
<string name="no_echo">No echo</string>
|
||||
|
@ -340,6 +341,7 @@
|
|||
<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_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_display_name_title">Display name</string>
|
||||
<string name="pref_user_name_title">Username</string>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<ContactsSource
|
||||
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
|
||||
android:mimeType="vnd.android.cursor.item/org.linphone.profile"
|
||||
android:icon="@drawable/linphone_logo"
|
||||
|
|
|
@ -69,6 +69,11 @@
|
|||
android:title="@string/pref_echo_canceller_calibration"
|
||||
android:key="@string/pref_echo_canceller_calibration_key"
|
||||
android:persistent="false"/>
|
||||
|
||||
<Preference
|
||||
android:title="@string/pref_echo_tester"
|
||||
android:key="@string/pref_echo_tester_key"
|
||||
android:persistent="false"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:title="@string/pref_adaptive_rate_control"
|
||||
|
@ -345,6 +350,11 @@
|
|||
android:key="@string/pref_remote_provisioning_key"
|
||||
android:inputType="textUri"
|
||||
android:persistent="false"/>
|
||||
|
||||
<Preference
|
||||
android:title="@string/pref_android_app_settings_title"
|
||||
android:key="@string/pref_android_app_settings_key"
|
||||
android:persistent="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
|
|
@ -69,11 +69,11 @@ public class AboutFragment extends Fragment implements OnClickListener {
|
|||
|
||||
sendLogButton = view.findViewById(R.id.send_log);
|
||||
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.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() {
|
||||
@Override
|
||||
|
@ -145,7 +145,7 @@ public class AboutFragment extends Fragment implements OnClickListener {
|
|||
lc.addListener(mListener);
|
||||
}
|
||||
|
||||
if (org.linphone.LinphoneActivity.isInstanciated()) {
|
||||
if (LinphoneActivity.isInstanciated()) {
|
||||
LinphoneActivity.instance().selectMenu(FragmentsAvailable.ABOUT);
|
||||
}
|
||||
|
||||
|
@ -154,8 +154,8 @@ public class AboutFragment extends Fragment implements OnClickListener {
|
|||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (org.linphone.LinphoneActivity.isInstanciated()) {
|
||||
LinphoneCore lc = org.linphone.LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
||||
if (LinphoneActivity.isInstanciated()) {
|
||||
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
||||
if (v == sendLogButton) {
|
||||
if (lc != null) {
|
||||
lc.uploadLogCollection();
|
||||
|
@ -174,6 +174,4 @@ public class AboutFragment extends Fragment implements OnClickListener {
|
|||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -53,8 +53,7 @@ public class AccountPreferencesFragment extends PreferencesListFragment {
|
|||
mPrefs = LinphonePreferences.instance();
|
||||
}
|
||||
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
PreferenceScreen screen = getPreferenceScreen();
|
||||
|
@ -69,7 +68,7 @@ public class AccountPreferencesFragment extends PreferencesListFragment {
|
|||
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.
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
*/
|
||||
import java.util.List;
|
||||
|
||||
import org.linphone.compatibility.Compatibility;
|
||||
import org.linphone.mediastream.Log;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
|
@ -68,31 +67,31 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
public BluetoothManager() {
|
||||
isBluetoothConnected = false;
|
||||
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;
|
||||
}
|
||||
|
||||
public void initBluetooth() {
|
||||
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;
|
||||
}
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
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(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
|
||||
mContext.registerReceiver(this, filter);
|
||||
Log.d("Bluetooth receiver started");
|
||||
Log.d("[Bluetooth] Receiver started");
|
||||
|
||||
startBluetooth();
|
||||
}
|
||||
|
||||
private void startBluetooth() {
|
||||
if (isBluetoothConnected) {
|
||||
Log.e("Bluetooth already started");
|
||||
Log.e("[Bluetooth] Already started, skipping...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -100,14 +99,14 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
|
||||
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
|
||||
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);
|
||||
}
|
||||
|
||||
mProfileListener = new BluetoothProfile.ServiceListener() {
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
if (profile == BluetoothProfile.HEADSET) {
|
||||
Log.d("Bluetooth headset connected");
|
||||
Log.d("[Bluetooth] Headset connected");
|
||||
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
||||
isBluetoothConnected = true;
|
||||
}
|
||||
|
@ -116,17 +115,17 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
if (profile == BluetoothProfile.HEADSET) {
|
||||
mBluetoothHeadset = null;
|
||||
isBluetoothConnected = false;
|
||||
Log.d("Bluetooth headset disconnected");
|
||||
Log.d("[Bluetooth] Headset disconnected");
|
||||
LinphoneManager.getInstance().routeAudioToReceiver();
|
||||
}
|
||||
}
|
||||
};
|
||||
boolean success = mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
|
||||
if (!success) {
|
||||
Log.e("Bluetooth getProfileProxy failed !");
|
||||
Log.e("[Bluetooth] getProfileProxy failed !");
|
||||
}
|
||||
} 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 (isBluetoothHeadsetAvailable()) {
|
||||
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.startBluetoothSco();
|
||||
}
|
||||
|
@ -180,12 +179,12 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
}
|
||||
if (ok) {
|
||||
if (retries > 0) {
|
||||
Log.d("Bluetooth route ok after " + retries + " retries");
|
||||
Log.d("[Bluetooth] Audio route ok after " + retries + " retries");
|
||||
} else {
|
||||
Log.d("Bluetooth route ok");
|
||||
Log.d("[Bluetooth] Audio route ok");
|
||||
}
|
||||
} else {
|
||||
Log.d("Bluetooth still not ok...");
|
||||
Log.d("[Bluetooth] Audio route still not ok...");
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
@ -212,7 +211,7 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
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;
|
||||
}
|
||||
|
@ -237,12 +236,12 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
mAudioManager.stopBluetoothSco();
|
||||
mAudioManager.setBluetoothScoOn(false);
|
||||
}
|
||||
Log.w("Bluetooth sco disconnected!");
|
||||
Log.w("[Bluetooth] SCO disconnected!");
|
||||
}
|
||||
}
|
||||
|
||||
public void stopBluetooth() {
|
||||
Log.w("Stopping bluetooth...");
|
||||
Log.w("[Bluetooth] Stopping...");
|
||||
isBluetoothConnected = false;
|
||||
|
||||
disableBluetoothSCO();
|
||||
|
@ -253,7 +252,7 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
}
|
||||
mBluetoothDevice = null;
|
||||
|
||||
Log.w("Bluetooth stopped!");
|
||||
Log.w("[Bluetooth] Stopped!");
|
||||
|
||||
if (LinphoneManager.isInstanciated()) {
|
||||
LinphoneManager.getInstance().routeAudioToReceiver();
|
||||
|
@ -266,7 +265,7 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
|
||||
try {
|
||||
mContext.unregisterReceiver(this);
|
||||
Log.d("Bluetooth receiver stopped");
|
||||
Log.d("[Bluetooth] Receiver stopped");
|
||||
} catch (Exception e) {}
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
|
@ -278,30 +277,30 @@ public class BluetoothManager extends BroadcastReceiver {
|
|||
return;
|
||||
|
||||
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);
|
||||
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
||||
Log.d("Bluetooth sco state => connected");
|
||||
Log.d("[Bluetooth] SCO state: connected");
|
||||
// LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH);
|
||||
isScoConnected = true;
|
||||
} 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);
|
||||
isScoConnected = false;
|
||||
} else {
|
||||
Log.d("Bluetooth sco state => " + state);
|
||||
Log.d("[Bluetooth] SCO state: " + state);
|
||||
}
|
||||
}
|
||||
else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
|
||||
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.STATE_DISCONNECTED);
|
||||
if (state == 0) {
|
||||
Log.d("Bluetooth state => disconnected");
|
||||
Log.d("[Bluetooth] State: disconnected");
|
||||
stopBluetooth();
|
||||
} else if (state == 2) {
|
||||
Log.d("Bluetooth state => connected");
|
||||
Log.d("[Bluetooth] State: connected");
|
||||
startBluetooth();
|
||||
} else {
|
||||
Log.d("Bluetooth state => " + state);
|
||||
Log.d("[Bluetooth] State: " + state);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
Integer buttonID = (Integer) args[1];
|
||||
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 LinphoneCoreListenerBase mListener;
|
||||
private DrawerLayout sideMenu;
|
||||
private boolean mProximitySensingEnabled;
|
||||
|
||||
public static CallActivity instance() {
|
||||
return instance;
|
||||
|
@ -800,8 +801,22 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
|||
}
|
||||
}
|
||||
|
||||
private void enableProximitySensing(boolean enable){
|
||||
if (enable){
|
||||
if (!mProximitySensingEnabled){
|
||||
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
mProximitySensingEnabled = true;
|
||||
}
|
||||
}else{
|
||||
if (mProximitySensingEnabled){
|
||||
mSensorManager.unregisterListener(this);
|
||||
mProximitySensingEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showAudioView() {
|
||||
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
enableProximitySensing(true);
|
||||
replaceFragmentVideoByAudio();
|
||||
displayAudioCall();
|
||||
showStatusBar();
|
||||
|
@ -816,7 +831,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
|||
}
|
||||
refreshInCallActions();
|
||||
|
||||
mSensorManager.unregisterListener(this);
|
||||
enableProximitySensing(false);
|
||||
replaceFragmentAudioByVideo();
|
||||
hideStatusBar();
|
||||
}
|
||||
|
@ -1173,7 +1188,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
|||
handleViewIntent();
|
||||
|
||||
if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
|
||||
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
enableProximitySensing(true);
|
||||
removeCallbacks();
|
||||
}
|
||||
}
|
||||
|
@ -1223,10 +1238,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
|||
mControlsHandler.removeCallbacks(mControls);
|
||||
}
|
||||
mControls = null;
|
||||
|
||||
if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
|
||||
mSensorManager.unregisterListener(this);
|
||||
}
|
||||
enableProximitySensing(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1239,7 +1251,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
|||
mControls = null;
|
||||
mControlsHandler = null;
|
||||
|
||||
mSensorManager.unregisterListener(this);
|
||||
enableProximitySensing(false);
|
||||
|
||||
unbindDrawables(findViewById(R.id.topLayout));
|
||||
instance = null;
|
||||
|
@ -1510,7 +1522,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
|
|||
private void displayConference(boolean isInConf){
|
||||
if(isInConf) {
|
||||
mControlsLayout.setVisibility(View.VISIBLE);
|
||||
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
enableProximitySensing(true);
|
||||
mActiveCallHeader.setVisibility(View.GONE);
|
||||
mNoCurrentCall.setVisibility(View.GONE);
|
||||
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.ByteArrayOutputStream;
|
||||
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.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -37,22 +42,29 @@ import org.linphone.core.LinphoneCore;
|
|||
import org.linphone.core.LinphoneCoreFactory;
|
||||
import org.linphone.core.LinphoneCoreListenerBase;
|
||||
import org.linphone.mediastream.Log;
|
||||
import org.linphone.ui.BubbleChat;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.Fragment;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.ExifInterface;
|
||||
import android.media.ThumbnailUtils;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
@ -61,9 +73,10 @@ import android.os.Parcelable;
|
|||
import android.provider.MediaStore;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.text.Editable;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -72,7 +85,6 @@ import android.view.ViewGroup;
|
|||
import android.view.ViewTreeObserver;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
|
@ -81,6 +93,7 @@ import android.widget.EditText;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
@ -111,6 +124,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
private SearchContactsListAdapter searchAdapter;
|
||||
private ListView messagesList, resultContactsSearch;
|
||||
private LayoutInflater inflater;
|
||||
private Bitmap defaultBitmap;
|
||||
|
||||
private boolean isEditMode = false;
|
||||
private LinphoneContact contact;
|
||||
|
@ -143,9 +157,10 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
}
|
||||
|
||||
//Initialize UI
|
||||
defaultBitmap = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.chat_picture_over);
|
||||
|
||||
contactName = (TextView) view.findViewById(R.id.contact_name);
|
||||
messagesList = (ListView) view.findViewById(R.id.chat_message_list);
|
||||
messagesList.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
|
||||
searchContactField = (EditText) view.findViewById(R.id.search_contact_field);
|
||||
resultContactsSearch = (ListView) view.findViewById(R.id.result_contacts);
|
||||
|
||||
|
@ -214,7 +229,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
LinphoneService.instance().removeMessageNotification();
|
||||
cr.markAsRead();
|
||||
adapter.addMessage(cr.getHistory(1)[0]);
|
||||
messagesList.setSelection(adapter.getCount()-1);
|
||||
|
||||
String externalBodyUrl = message.getExternalBodyUrl();
|
||||
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) {
|
||||
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
||||
|
||||
LinphoneAddress lAddress = null;
|
||||
if(sipUri == null){
|
||||
if (sipUri == null) {
|
||||
initNewChatConversation();
|
||||
} else {
|
||||
try {
|
||||
|
@ -477,7 +367,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
}
|
||||
|
||||
private void displayMessageList() {
|
||||
if(chatRoom != null) {
|
||||
if (chatRoom != null) {
|
||||
if (adapter != null) {
|
||||
adapter.refreshHistory();
|
||||
} else {
|
||||
|
@ -488,7 +378,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
}
|
||||
|
||||
private void displayChatHeader(LinphoneAddress address) {
|
||||
if(contact != null) {
|
||||
if (contact != null) {
|
||||
contactName.setText(contact.getFullName());
|
||||
} else if(address != null){
|
||||
contactName.setText(LinphoneUtils.getAddressDisplayName(address));
|
||||
|
@ -580,6 +470,10 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
if (adapter != null) {
|
||||
adapter.destroy();
|
||||
}
|
||||
if (defaultBitmap != null) {
|
||||
defaultBitmap.recycle();
|
||||
defaultBitmap = null;
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
@ -618,7 +512,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
String draft = getArguments().getString("messageDraft");
|
||||
message.setText(draft);
|
||||
|
||||
if(!newChatConversation) {
|
||||
if (!newChatConversation) {
|
||||
initChatRoom(sipUri);
|
||||
searchContactField.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();
|
||||
for(int i=0; i<size; i++) {
|
||||
messagesList.setItemChecked(i,isSelectAll);
|
||||
for (int i = 0; i < size; i++) {
|
||||
messagesList.setItemChecked(i, isSelectAll);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -642,8 +536,8 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
|
||||
private void removeChats(){
|
||||
int size = messagesList.getAdapter().getCount();
|
||||
for(int i=0; i<size; i++) {
|
||||
if(messagesList.isItemChecked(i)){
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (messagesList.isItemChecked(i)) {
|
||||
LinphoneChatMessage message = (LinphoneChatMessage) messagesList.getAdapter().getItem(i);
|
||||
chatRoom.deleteMessage(message);
|
||||
}
|
||||
|
@ -654,7 +548,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
int id = v.getId();
|
||||
|
||||
|
||||
if (id == R.id.back_to_call) {
|
||||
LinphoneActivity.instance().resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
|
||||
return;
|
||||
|
@ -827,7 +721,9 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
txt = message.getText();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1038,7 +934,492 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
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 {
|
||||
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 LayoutInflater mInflater;
|
||||
|
||||
|
@ -1089,24 +1470,26 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
|
|||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view = null;
|
||||
ContactAddress contact;
|
||||
ViewHolder holder = null;
|
||||
|
||||
do {
|
||||
contact = getItem(position);
|
||||
} while (contact == null);
|
||||
|
||||
if (convertView != null) {
|
||||
view = convertView;
|
||||
holder = (ViewHolder) view.getTag();
|
||||
} else {
|
||||
view = mInflater.inflate(R.layout.search_contact_cell, parent, false);
|
||||
holder = new ViewHolder(view);
|
||||
view.setTag(holder);
|
||||
}
|
||||
|
||||
final String a = contact.address;
|
||||
LinphoneContact c = contact.contact;
|
||||
|
||||
TextView name = (TextView) view.findViewById(R.id.contact_name);
|
||||
name.setText(c.getFullName());
|
||||
|
||||
TextView address = (TextView) view.findViewById(R.id.contact_address);
|
||||
address.setText(a);
|
||||
holder.name.setText(c.getFullName());
|
||||
holder.address.setText(a);
|
||||
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.linphone.mediastream.Log;
|
|||
|
||||
import android.app.Dialog;
|
||||
import android.app.Fragment;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
|
@ -117,15 +118,16 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
|||
}
|
||||
}
|
||||
|
||||
private void removeChatsConversation(){
|
||||
private void removeChatsConversation() {
|
||||
int size = chatList.getAdapter().getCount();
|
||||
for(int i=0; i<size; i++) {
|
||||
if(chatList.isItemChecked(i)){
|
||||
View item = chatList.getAdapter().getView(i, null, null);
|
||||
if(item != null) {
|
||||
LinphoneChatRoom chatroom = LinphoneManager.getLc().getOrCreateChatRoom(item.getTag().toString());
|
||||
if (chatroom != null)
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (chatList.isItemChecked(i)) {
|
||||
String sipUri = chatList.getAdapter().getItem(i).toString();
|
||||
if (sipUri != null) {
|
||||
LinphoneChatRoom chatroom = LinphoneManager.getLc().getOrCreateChatRoom(sipUri);
|
||||
if (chatroom != null) {
|
||||
chatroom.deleteHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +243,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
|||
if (info == null || info.targetView == null) {
|
||||
return false;
|
||||
}
|
||||
String sipUri = (String) info.targetView.getTag();
|
||||
String sipUri = chatList.getAdapter().getItem(info.position).toString();
|
||||
|
||||
LinphoneActivity.instance().removeFromChatList(sipUri);
|
||||
mConversations = LinphoneActivity.instance().getChatList();
|
||||
|
@ -331,7 +333,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
|||
|
||||
@Override
|
||||
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) {
|
||||
LinphoneActivity.instance().displayChat(sipUri);
|
||||
|
@ -339,7 +341,24 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
|||
}
|
||||
|
||||
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() {}
|
||||
|
||||
public int getCount() {
|
||||
|
@ -347,7 +366,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
|||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
return position;
|
||||
return mConversations.get(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) {
|
||||
View view = null;
|
||||
ViewHolder holder = null;
|
||||
String sipUri = mConversations.get(position);
|
||||
|
||||
if (convertView != null) {
|
||||
view = convertView;
|
||||
holder = (ViewHolder) view.getTag();
|
||||
} else {
|
||||
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;
|
||||
try {
|
||||
address = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri);
|
||||
} catch (LinphoneCoreException e) {
|
||||
Log.e("Chat view cannot parse address",e);
|
||||
Log.e("Chat view cannot parse address", e);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
@ -378,57 +399,55 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
|||
String message = "";
|
||||
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);
|
||||
int unreadMessagesCount = chatRoom.getUnreadMessagesCount();
|
||||
LinphoneChatMessage[] history = chatRoom.getHistory(1);
|
||||
LinphoneChatMessage msg = history[0];
|
||||
|
||||
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();
|
||||
date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format)));
|
||||
lastMessageView.setText("");
|
||||
holder.date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format)));
|
||||
holder.lastMessageView.setText("");
|
||||
} else if (msg.getText() != null && msg.getText().length() > 0 ){
|
||||
message = msg.getText();
|
||||
lastMessageView.setBackgroundResource(0);
|
||||
holder.lastMessageView.setBackgroundResource(0);
|
||||
time = msg.getTime();
|
||||
date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format)));
|
||||
lastMessageView.setText(message);
|
||||
holder.date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format)));
|
||||
holder.lastMessageView.setText(message);
|
||||
}
|
||||
|
||||
displayName.setSelected(true); // For animation
|
||||
displayName.setText(contact == null ? LinphoneUtils.getAddressDisplayName(address) : contact.getFullName());
|
||||
holder.displayName.setSelected(true); // For animation
|
||||
holder.displayName.setText(contact == null ? LinphoneUtils.getAddressDisplayName(address) : contact.getFullName());
|
||||
|
||||
|
||||
if (contact != null) {
|
||||
LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
|
||||
Bitmap photo = contact.getPhoto();
|
||||
if (photo != null) {
|
||||
holder.contactPicture.setImageBitmap(photo);
|
||||
} else {
|
||||
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
|
||||
}
|
||||
} else {
|
||||
contactPicture.setImageResource(R.drawable.avatar);
|
||||
holder.contactPicture.setImageResource(R.drawable.avatar);
|
||||
}
|
||||
|
||||
if (unreadMessagesCount > 0) {
|
||||
unreadMessages.setVisibility(View.VISIBLE);
|
||||
unreadMessages.setText(String.valueOf(unreadMessagesCount));
|
||||
if(unreadMessagesCount > 99){
|
||||
unreadMessages.setTextSize(12);
|
||||
holder.unreadMessages.setVisibility(View.VISIBLE);
|
||||
holder.unreadMessages.setText(String.valueOf(unreadMessagesCount));
|
||||
if (unreadMessagesCount > 99) {
|
||||
holder.unreadMessages.setTextSize(12);
|
||||
}
|
||||
displayName.setTypeface(null, Typeface.BOLD);
|
||||
holder.displayName.setTypeface(null, Typeface.BOLD);
|
||||
} else {
|
||||
unreadMessages.setVisibility(View.GONE);
|
||||
displayName.setTypeface(null, Typeface.NORMAL);
|
||||
holder.unreadMessages.setVisibility(View.GONE);
|
||||
holder.displayName.setTypeface(null, Typeface.NORMAL);
|
||||
}
|
||||
|
||||
if (isEditMode) {
|
||||
unreadMessages.setVisibility(View.GONE);
|
||||
select.setVisibility(View.VISIBLE);
|
||||
select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
holder.unreadMessages.setVisibility(View.GONE);
|
||||
holder.select.setVisibility(View.VISIBLE);
|
||||
holder.select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||
chatList.setItemChecked(position, b);
|
||||
|
@ -450,13 +469,13 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
|
|||
}
|
||||
});
|
||||
if(chatList.isItemChecked(position)) {
|
||||
select.setChecked(true);
|
||||
holder.select.setChecked(true);
|
||||
} else {
|
||||
select.setChecked(false);
|
||||
holder.select.setChecked(false);
|
||||
}
|
||||
} else {
|
||||
if (unreadMessagesCount > 0) {
|
||||
unreadMessages.setVisibility(View.VISIBLE);
|
||||
holder.unreadMessages.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
organization = (TextView) view.findViewById(R.id.contactOrganization);
|
||||
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
|
||||
String org = contact.getOrganization();
|
||||
if (org != null && !org.isEmpty()) {
|
||||
if (org != null && !org.isEmpty() && isOrgVisible) {
|
||||
organization.setText(org);
|
||||
} else {
|
||||
organization.setVisibility(View.GONE);
|
||||
|
|
|
@ -204,9 +204,16 @@ public class ContactEditorFragment extends Fragment {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
organization = (EditText) view.findViewById(R.id.contactOrganization);
|
||||
if (!isNewContact) {
|
||||
organization.setText(contact.getOrganization());
|
||||
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) {
|
||||
organization.setText(contact.getOrganization());
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNewContact) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.linphone.core.PresenceActivityType;
|
|||
|
||||
import android.app.Dialog;
|
||||
import android.app.Fragment;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
|
@ -416,6 +417,28 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O
|
|||
}
|
||||
|
||||
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;
|
||||
String[] sections;
|
||||
ArrayList<String> sectionsList;
|
||||
|
@ -461,57 +484,57 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O
|
|||
LinphoneContact contact = (LinphoneContact) getItem(position);
|
||||
if (contact == null) return null;
|
||||
|
||||
ViewHolder holder = null;
|
||||
if (convertView != null) {
|
||||
view = convertView;
|
||||
holder = (ViewHolder) view.getTag();
|
||||
} else {
|
||||
view = mInflater.inflate(R.layout.contact_cell, parent, false);
|
||||
holder = new ViewHolder(view);
|
||||
view.setTag(holder);
|
||||
}
|
||||
|
||||
CheckBox delete = (CheckBox) view.findViewById(R.id.delete);
|
||||
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);
|
||||
holder.name.setText(contact.getFullName());
|
||||
|
||||
if (getPositionForSection(getSectionForPosition(position)) != position) {
|
||||
separator.setVisibility(View.GONE);
|
||||
holder.separator.setVisibility(View.GONE);
|
||||
} else {
|
||||
separator.setVisibility(View.VISIBLE);
|
||||
holder.separator.setVisibility(View.VISIBLE);
|
||||
String fullName = contact.getFullName();
|
||||
if (fullName != null && !fullName.isEmpty()) {
|
||||
separatorText.setText(String.valueOf(fullName.charAt(0)));
|
||||
holder.separatorText.setText(String.valueOf(fullName.charAt(0)));
|
||||
}
|
||||
}
|
||||
|
||||
if (contact.isInLinphoneFriendList()) {
|
||||
linphoneFriend.setVisibility(View.VISIBLE);
|
||||
holder.linphoneFriend.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
linphoneFriend.setVisibility(View.GONE);
|
||||
holder.linphoneFriend.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
ImageView icon = (ImageView) view.findViewById(R.id.contact_picture);
|
||||
if (contact.hasPhoto()) {
|
||||
LinphoneUtils.setImagePictureFromUri(getActivity(), icon, contact.getPhotoUri(), contact.getThumbnailUri());
|
||||
} else if (contact.getPhotoUri() != null) {
|
||||
icon.setImageURI(contact.getPhotoUri());
|
||||
Bitmap photo = contact.getPhoto();
|
||||
if (photo != null) {
|
||||
holder.contactPicture.setImageBitmap(photo);
|
||||
} else {
|
||||
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
|
||||
}
|
||||
} else {
|
||||
icon.setImageResource(R.drawable.avatar);
|
||||
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();
|
||||
if (org != null && !org.isEmpty()) {
|
||||
organization.setText(org);
|
||||
organization.setVisibility(View.VISIBLE);
|
||||
if (org != null && !org.isEmpty() && isOrgVisible) {
|
||||
holder.organization.setText(org);
|
||||
holder.organization.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
organization.setVisibility(View.GONE);
|
||||
holder.organization.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (isEditMode) {
|
||||
delete.setVisibility(View.VISIBLE);
|
||||
delete.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
holder.delete.setVisibility(View.VISIBLE);
|
||||
holder.delete.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||
contactsList.setItemChecked(position, b);
|
||||
|
@ -533,29 +556,28 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O
|
|||
}
|
||||
});
|
||||
if (contactsList.isItemChecked(position)) {
|
||||
delete.setChecked(true);
|
||||
holder.delete.setChecked(true);
|
||||
} else {
|
||||
delete.setChecked(false);
|
||||
holder.delete.setChecked(false);
|
||||
}
|
||||
} else {
|
||||
delete.setVisibility(View.GONE);
|
||||
holder.delete.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
ImageView friendStatus = (ImageView) view.findViewById(R.id.friendStatus);
|
||||
LinphoneFriend[] friends = LinphoneManager.getLc().getFriendList();
|
||||
if (!ContactsManager.getInstance().isContactPresenceDisabled() && friends != null) {
|
||||
friendStatus.setVisibility(View.VISIBLE);
|
||||
holder.friendStatus.setVisibility(View.VISIBLE);
|
||||
PresenceActivityType presenceActivity = friends[0].getPresenceModel().getActivity().getType();
|
||||
if (presenceActivity == PresenceActivityType.Online) {
|
||||
friendStatus.setImageResource(R.drawable.led_connected);
|
||||
holder.friendStatus.setImageResource(R.drawable.led_connected);
|
||||
} else if (presenceActivity == PresenceActivityType.Busy) {
|
||||
friendStatus.setImageResource(R.drawable.led_error);
|
||||
holder.friendStatus.setImageResource(R.drawable.led_error);
|
||||
} else if (presenceActivity == PresenceActivityType.Away) {
|
||||
friendStatus.setImageResource(R.drawable.led_inprogress);
|
||||
holder.friendStatus.setImageResource(R.drawable.led_inprogress);
|
||||
} else if (presenceActivity == PresenceActivityType.Offline) {
|
||||
friendStatus.setImageResource(R.drawable.led_disconnected);
|
||||
holder.friendStatus.setImageResource(R.drawable.led_disconnected);
|
||||
} 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.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.linphone.compatibility.Compatibility;
|
||||
import org.linphone.core.LinphoneAddress;
|
||||
import org.linphone.core.LinphoneCore;
|
||||
import org.linphone.core.LinphoneFriend;
|
||||
|
@ -38,11 +39,13 @@ import android.content.ContentResolver;
|
|||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.CommonDataKinds;
|
||||
import android.provider.ContactsContract.Data;
|
||||
|
||||
interface ContactsUpdatedListener {
|
||||
|
@ -228,14 +231,13 @@ public class ContactsManager extends ContentObserver {
|
|||
contactsFetchTask.execute();
|
||||
}
|
||||
|
||||
|
||||
private class ContactsFetchTask extends AsyncTask<Void, List<LinphoneContact>, List<LinphoneContact>> {
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<LinphoneContact> doInBackground(Void... params) {
|
||||
List<LinphoneContact> contacts = new ArrayList<LinphoneContact>();
|
||||
|
||||
if (hasContactsAccess()) {
|
||||
Cursor c = Compatibility.getContactsCursor(contentResolver, null);
|
||||
Cursor c = getContactsCursor(contentResolver);
|
||||
if (c != null) {
|
||||
while (c.moveToNext()) {
|
||||
String id = c.getString(c.getColumnIndex(Data.CONTACT_ID));
|
||||
|
@ -367,4 +369,38 @@ public class ContactsManager extends ContentObserver {
|
|||
public String getString(int 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.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -349,6 +350,22 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
|||
}
|
||||
|
||||
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) {
|
||||
|
||||
}
|
||||
|
@ -401,23 +418,20 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
|||
|
||||
public View getView(final int position, View convertView, ViewGroup parent) {
|
||||
View view = null;
|
||||
ViewHolder holder;
|
||||
ViewHolder holder = null;
|
||||
|
||||
if (convertView != null) {
|
||||
view = convertView;
|
||||
holder = (ViewHolder) view.getTag();
|
||||
} else {
|
||||
view = mInflater.inflate(R.layout.history_cell, parent,false);
|
||||
holder = new ViewHolder();
|
||||
holder.contact = (TextView) view.findViewById(R.id.sip_uri);
|
||||
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);
|
||||
holder = new ViewHolder(view);
|
||||
view.setTag(holder);
|
||||
}
|
||||
|
||||
final LinphoneCallLog log = mLogs.get(position);
|
||||
long timestamp = log.getTimestamp();
|
||||
final LinphoneAddress address;
|
||||
LinphoneAddress address;
|
||||
|
||||
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);
|
||||
String displayName = null;
|
||||
final String sipUri = address.asString();
|
||||
if(c != null){
|
||||
if (c != null) {
|
||||
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 {
|
||||
holder.contactPicture.setImageResource(R.drawable.avatar);
|
||||
}
|
||||
|
@ -469,7 +492,6 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
|||
} else {
|
||||
holder.contact.setText(displayName);
|
||||
}
|
||||
//view.setTag(sipUri);
|
||||
|
||||
if (isEditMode) {
|
||||
holder.select.setVisibility(View.VISIBLE);
|
||||
|
@ -512,16 +534,7 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
|
|||
}
|
||||
});
|
||||
}
|
||||
view.setTag(holder);
|
||||
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_RECORD_AUDIO_ECHO_CANCELLER = 209;
|
||||
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;
|
||||
|
||||
|
@ -1178,7 +1179,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
|
|||
public void checkAndRequestReadContactsPermission() {
|
||||
checkAndRequestPermission(Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_CONTACTS);
|
||||
}
|
||||
|
||||
|
||||
private boolean willContactsPermissionBeAsked() {
|
||||
return LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.READ_CONTACTS) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS);
|
||||
}
|
||||
|
@ -1191,6 +1192,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
|
|||
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() {
|
||||
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:
|
||||
((SettingsFragment) fragment).enableDeviceRingtone(grantResults[0] == PackageManager.PERMISSION_GRANTED);
|
||||
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;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -38,8 +40,10 @@ import android.content.ContentResolver;
|
|||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.ContactsContract.CommonDataKinds;
|
||||
|
||||
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> changesToCommit2;
|
||||
private boolean hasSipAddress;
|
||||
private Bitmap photoBitmap, thumbnailBitmap;
|
||||
|
||||
public LinphoneContact() {
|
||||
addresses = new ArrayList<LinphoneNumberOrAddress>();
|
||||
|
@ -66,6 +71,19 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
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
|
||||
public int compareTo(LinphoneContact contact) {
|
||||
String fullName = getFullName();
|
||||
|
@ -167,21 +185,62 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
}
|
||||
|
||||
public void setPhotoUri(Uri uri) {
|
||||
if (uri.equals(photoUri)) return;
|
||||
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() {
|
||||
return photoUri;
|
||||
}
|
||||
|
||||
public Bitmap getPhotoBitmap() {
|
||||
return photoBitmap;
|
||||
}
|
||||
|
||||
public void setThumbnailUri(Uri uri) {
|
||||
if (uri.equals(thumbnailUri)) return;
|
||||
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() {
|
||||
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) {
|
||||
if (photo != null) {
|
||||
if (isAndroidContact()) {
|
||||
|
@ -419,6 +478,7 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
friend.edit();
|
||||
friend.setFamilyName(lastName);
|
||||
friend.setGivenName(firstName);
|
||||
friend.setName(fullName);
|
||||
|
||||
for (LinphoneAddress address : friend.getAddresses()) {
|
||||
friend.removeAddress(address);
|
||||
|
@ -443,25 +503,21 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
friend.addPhoneNumber(noa.getValue());
|
||||
}
|
||||
}
|
||||
if (friend.getAddress() != null) {
|
||||
friend.setName(fullName);
|
||||
}
|
||||
friend.done();
|
||||
|
||||
if (friend.getAddress() != null) {
|
||||
if (lc.findFriendByAddress(friend.getAddress().asString()) == null) {
|
||||
try {
|
||||
lc.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) {
|
||||
Log.e(e);
|
||||
}
|
||||
if (!friend.isAlreadyPresentInFriendList()) {
|
||||
try {
|
||||
LinphoneManager.getLcIfManagerNotDestroyedOrNull().addFriend(friend);
|
||||
} catch (LinphoneCoreException 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();
|
||||
}
|
||||
}
|
||||
|
||||
public void save() {
|
||||
|
|
|
@ -30,13 +30,10 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import org.linphone.compatibility.Compatibility;
|
||||
import org.linphone.core.CallDirection;
|
||||
import org.linphone.core.LinphoneAddress;
|
||||
import org.linphone.core.LinphoneBuffer;
|
||||
|
@ -77,7 +74,6 @@ import org.linphone.tools.OpenH264DownloadHelper;
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
|
@ -87,10 +83,6 @@ import android.content.Intent;
|
|||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
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.MediaPlayer;
|
||||
import android.net.ConnectivityManager;
|
||||
|
@ -105,10 +97,6 @@ import android.preference.CheckBoxPreference;
|
|||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
|
@ -141,6 +129,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
private String basePath;
|
||||
private static boolean sExited;
|
||||
private boolean mAudioFocused;
|
||||
private boolean echoTesterIsRunning;
|
||||
private int mLastNetworkType=-1;
|
||||
private ConnectivityManager mConnectivityManager;
|
||||
private BroadcastReceiver mKeepAliveReceiver;
|
||||
|
@ -164,6 +153,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
|
||||
protected LinphoneManager(final Context c) {
|
||||
sExited = false;
|
||||
echoTesterIsRunning = false;
|
||||
mServiceContext = c;
|
||||
basePath = c.getFilesDir().getAbsolutePath();
|
||||
mLPConfigXsd = basePath + "/lpconfig.xsd";
|
||||
|
@ -217,8 +207,8 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
mCodecDownloader = LinphoneCoreFactory.instance().createOpenH264DownloadHelper();
|
||||
mCodecListener = new OpenH264DownloadHelperListener() {
|
||||
ProgressDialog progress;
|
||||
int box = 1;
|
||||
int ctxt = 0;
|
||||
int box = 1;
|
||||
|
||||
@Override
|
||||
public void OnProgress(final int current, final int max) {
|
||||
|
@ -240,8 +230,10 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
progress.dismiss();
|
||||
progress = null;
|
||||
LinphoneManager.getLc().reloadMsPlugins(null);
|
||||
if (ohcodec.getUserDataSize() > box && ohcodec.getUserData(box) != null)
|
||||
((CheckBoxPreference)ohcodec.getUserData(box)).setSummary(mCodecDownloader.getLicenseMessage());
|
||||
if (ohcodec.getUserDataSize() > box && ohcodec.getUserData(box) != null) {
|
||||
((CheckBoxPreference) ohcodec.getUserData(box)).setSummary(mCodecDownloader.getLicenseMessage());
|
||||
((CheckBoxPreference) ohcodec.getUserData(box)).setTitle("OpenH264");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -688,6 +680,32 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
Log.e(e, "Cannot start linphone");
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
mLc = lc;
|
||||
|
@ -742,7 +760,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
mLc.migrateCallLogs();
|
||||
|
||||
if (mServiceContext.getResources().getBoolean(R.bool.enable_push_id)) {
|
||||
Compatibility.initPushNotificationService(mServiceContext);
|
||||
initPushNotificationsService();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1020,7 +1038,16 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
}
|
||||
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")
|
||||
public void callState(final LinphoneCore lc,final LinphoneCall call, final State state, final String message) {
|
||||
Log.i("New call state [",state,"]");
|
||||
|
@ -1056,7 +1083,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
if (state == State.Connected) {
|
||||
if (mLc.getCallsNb() == 1) {
|
||||
requestAudioFocus();
|
||||
Compatibility.setAudioManagerInCallMode(mAudioManager);
|
||||
setAudioManagerInCallMode();
|
||||
}
|
||||
|
||||
if (Hacks.needSoftvolume()) {
|
||||
|
@ -1066,7 +1093,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
}
|
||||
|
||||
if (state == State.OutgoingEarlyMedia) {
|
||||
Compatibility.setAudioManagerInCallMode(mAudioManager);
|
||||
setAudioManagerInCallMode();
|
||||
}
|
||||
|
||||
if (state == State.CallReleased || state == State.Error) {
|
||||
|
@ -1146,7 +1173,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
|
||||
public void startEcCalibration(LinphoneCoreListener l) throws LinphoneCoreException {
|
||||
routeAudioToSpeaker();
|
||||
Compatibility.setAudioManagerInCallMode((AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE));
|
||||
setAudioManagerInCallMode();
|
||||
Log.i("Set audio mode on 'Voice Communication'");
|
||||
int oldVolume = mAudioManager.getStreamVolume(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);
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
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() {
|
||||
if (sExited || instance == null) {
|
||||
// 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();
|
||||
|
||||
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);
|
||||
|
||||
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.pm.PackageManager;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.CheckBoxPreference;
|
||||
|
@ -58,6 +59,7 @@ import android.preference.Preference.OnPreferenceChangeListener;
|
|||
import android.preference.Preference.OnPreferenceClickListener;
|
||||
import android.preference.PreferenceCategory;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.provider.Settings;
|
||||
|
||||
/**
|
||||
* @author Sylvain Berfini
|
||||
|
@ -611,10 +613,52 @@ public class SettingsFragment extends PreferencesListFragment {
|
|||
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() {
|
||||
try {
|
||||
if (LinphoneManager.getInstance().getEchoTesterStatus())
|
||||
stopEchoTester();
|
||||
LinphoneManager.getInstance().startEcCalibration(mListener);
|
||||
} catch (LinphoneCoreException e) {
|
||||
Log.e(e);
|
||||
|
@ -642,7 +686,9 @@ public class SettingsFragment extends PreferencesListFragment {
|
|||
codecs.removeAll();
|
||||
|
||||
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
|
||||
|
||||
final OpenH264DownloadHelper mCodecDownloader = LinphoneManager.getInstance().getOpenH264DownloadHelper();
|
||||
|
||||
for (final PayloadType pt : lc.getVideoCodecs()) {
|
||||
final CheckBoxPreference codec = new CheckBoxPreference(getActivity());
|
||||
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.setTitle("OpenH264");
|
||||
}
|
||||
codec.setChecked(lc.isPayloadTypeEnabled(pt));
|
||||
|
||||
codec.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
||||
|
@ -670,9 +718,9 @@ public class SettingsFragment extends PreferencesListFragment {
|
|||
try {
|
||||
if (enable && Version.getCpuAbis().contains("armeabi-v7a") && !Version.getCpuAbis().contains("x86")
|
||||
&& pt.getMime().equals("H264") && !mCodecDownloader.isCodecFound()) {
|
||||
LinphoneManager.getInstance().getOpenH264DownloadHelper().setOpenH264HelperListener(LinphoneManager.getInstance().getOpenH264HelperListener());
|
||||
LinphoneManager.getInstance().getOpenH264DownloadHelper().setUserData(0,LinphoneManager.getInstance().getContext());
|
||||
LinphoneManager.getInstance().getOpenH264DownloadHelper().setUserData(1,codec);
|
||||
mCodecDownloader.setOpenH264HelperListener(LinphoneManager.getInstance().getOpenH264HelperListener());
|
||||
mCodecDownloader.setUserData(0,LinphoneManager.getInstance().getContext());
|
||||
mCodecDownloader.setUserData(1,codec);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(LinphoneManager.getInstance().getContext());
|
||||
builder.setCancelable(false);
|
||||
|
@ -702,7 +750,6 @@ public class SettingsFragment extends PreferencesListFragment {
|
|||
|
||||
codecs.addPreference(codec);
|
||||
}
|
||||
|
||||
((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_initiate_call_with_video_key))).setChecked(mPrefs.shouldInitiateVideoCall());
|
||||
|
@ -1146,6 +1193,24 @@ public class SettingsFragment extends PreferencesListFragment {
|
|||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
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() {
|
||||
@Override
|
||||
|
@ -1182,9 +1247,11 @@ public class SettingsFragment extends PreferencesListFragment {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (LinphoneManager.getInstance().getEchoTesterStatus())
|
||||
stopEchoTester();
|
||||
LinphoneActivity.instance().hideTopBar();
|
||||
super.onPause();
|
||||
}
|
||||
|
|
|
@ -478,7 +478,10 @@ public class StatusFragment extends Fragment {
|
|||
PayloadType payloadAudio = params.getUsedAudioCodec();
|
||||
PayloadType payloadVideo = params.getUsedVideoCodec();
|
||||
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");
|
||||
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.
|
||||
*/
|
||||
|
||||
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.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
@ -29,15 +36,6 @@ import android.widget.Button;
|
|||
import android.widget.ProgressBar;
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
import org.linphone.R;
|
||||
import org.linphone.compatibility.Compatibility;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -53,7 +53,7 @@ public class LinphoneLoginFragment extends Fragment implements OnClickListener,
|
|||
password = (EditText) view.findViewById(R.id.assistant_password);
|
||||
password.addTextChangedListener(this);
|
||||
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());
|
||||
displayName = (EditText) view.findViewById(R.id.assistant_display_name);
|
||||
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 org.linphone.R;
|
||||
import org.linphone.mediastream.Log;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
|
||||
|
@ -119,21 +115,6 @@ public class ApiElevenPlus {
|
|||
|
||||
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) {
|
||||
Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
|
||||
|
|
|
@ -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)
|
||||
public class ApiSixteenPlus {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Notification createMessageNotification(Context context,
|
||||
int msgCount, String msgSender, String msg, Bitmap contactIcon,
|
||||
PendingIntent intent) {
|
||||
|
|
|
@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
@TargetApi(21)
|
||||
public class ApiTwentyOnePlus {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Notification createMessageNotification(Context context,
|
||||
int msgCount, String msgSender, String msg, Bitmap contactIcon,
|
||||
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
|
||||
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 android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.PowerManager;
|
||||
import android.preference.Preference;
|
||||
import android.provider.Settings;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
/**
|
||||
* @author Sylvain Berfini
|
||||
*/
|
||||
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) {
|
||||
Notification notif = null;
|
||||
|
||||
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
||||
return ApiTwentyOnePlus.createSimpleNotification(context, title, text, intent);
|
||||
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||
notif = ApiSixteenPlus.createSimpleNotification(context, title, text, intent);
|
||||
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
|
||||
notif = ApiElevenPlus.createSimpleNotification(context, title, text, intent);
|
||||
} else {
|
||||
notif = ApiFivePlus.createSimpleNotification(context, title, text, intent);
|
||||
notif = ApiElevenPlus.createSimpleNotification(context, title, text, intent);
|
||||
}
|
||||
return notif;
|
||||
}
|
||||
|
||||
public static Notification createMessageNotification(Context context, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
|
||||
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));
|
||||
}
|
||||
|
||||
Notification notif = null;
|
||||
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
||||
return ApiTwentyOnePlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
|
||||
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||
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 {
|
||||
notif = ApiFivePlus.createMessageNotification(context, title, msg, intent);
|
||||
notif = ApiElevenPlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
|
||||
}
|
||||
return notif;
|
||||
}
|
||||
|
||||
public static Notification createInCallNotification(Context context, String title, String msg, int iconID, Bitmap contactIcon, String contactName, PendingIntent intent) {
|
||||
Notification notif = null;
|
||||
|
||||
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
|
||||
return ApiTwentyOnePlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
|
||||
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||
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 {
|
||||
notif = ApiFivePlus.createInCallNotification(context, title, msg, iconID, intent);
|
||||
notif = ApiElevenPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
|
||||
}
|
||||
return notif;
|
||||
}
|
||||
|
@ -211,20 +74,11 @@ public class Compatibility {
|
|||
return ApiTwentyOnePlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent,priority);
|
||||
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||
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 {
|
||||
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) {
|
||||
if (Version.sdkAboveOrEqual(Version.API08_FROYO_22)) {
|
||||
CompatibilityScaleGestureDetector csgd = new CompatibilityScaleGestureDetector(context);
|
||||
|
@ -233,109 +87,13 @@ public class Compatibility {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, OnGlobalLayoutListener keyboardListener) {
|
||||
if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
|
||||
ApiSixteenPlus.removeGlobalLayoutListener(viewTreeObserver, keyboardListener);
|
||||
} else {
|
||||
ApiFivePlus.removeGlobalLayoutListener(viewTreeObserver, 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();
|
||||
viewTreeObserver.removeGlobalOnLayoutListener(keyboardListener);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,4 +112,12 @@ public class Compatibility {
|
|||
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
|
||||
protected void onError(Context context, String errorId) {
|
||||
initLogger(context);
|
||||
Log.e("Error while registering push notification : " + errorId);
|
||||
Log.e("[Push Notification] Error while registering: " + errorId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMessage(Context context, Intent intent) {
|
||||
initLogger(context);
|
||||
Log.d("Push notification received");
|
||||
Log.d("[Push Notification] Received");
|
||||
|
||||
if (!LinphoneService.isReady()) {
|
||||
startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
|
||||
|
@ -79,7 +79,7 @@ public class GCMService extends GCMBaseIntentService {
|
|||
@Override
|
||||
protected void onRegistered(Context context, String regId) {
|
||||
initLogger(context);
|
||||
Log.d("Registered push notification : " + regId);
|
||||
Log.d("[Push Notification] Registered: " + regId);
|
||||
|
||||
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public class GCMService extends GCMBaseIntentService {
|
|||
@Override
|
||||
protected void onUnregistered(Context context, String regId) {
|
||||
initLogger(context);
|
||||
Log.w("Unregistered push notification : " + regId);
|
||||
Log.w("[Push Notification] Unregistered: " + regId);
|
||||
|
||||
LinphonePreferences.instance().setPushNotificationRegistrationID(null);
|
||||
}
|
||||
|
|
|
@ -162,8 +162,7 @@ public class TutorialCardDavSync extends Activity implements OnClickListener, Li
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onLinphoneFriendSyncStatusChanged(LinphoneFriendList list,
|
||||
org.linphone.core.LinphoneFriendList.State status, String message) {
|
||||
public void onLinphoneFriendSyncStatusChanged(LinphoneFriendList list, LinphoneFriendList.State status, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
String msg = "Sync status changed: " + status.toString() + " (" + message + ")";
|
||||
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>
|
||||
<exec executable="bash" unless:set="has.crashed">
|
||||
<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>
|
||||
|
||||
<zip destfile="${archive.name}.zip">
|
||||
|
|
Loading…
Reference in a new issue