diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 53d5f3619..84c05cc03 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -37,7 +37,10 @@
-
+
+
+
+
@@ -45,6 +48,7 @@
@@ -56,7 +60,7 @@
-
+ />
@@ -64,14 +68,16 @@
+
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -182,8 +207,8 @@
-
-
diff --git a/liblinphone_tester/src/org/linphone/tester/WrapperTester.java b/liblinphone_tester/src/org/linphone/tester/WrapperTester.java
index 6a999a41c..e9ea4b869 100644
--- a/liblinphone_tester/src/org/linphone/tester/WrapperTester.java
+++ b/liblinphone_tester/src/org/linphone/tester/WrapperTester.java
@@ -3,6 +3,7 @@ package org.linphone.tester;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListenerBase;
+import org.linphone.core.LinphoneFriend;
import org.linphone.core.PayloadType;
import android.test.AndroidTestCase;
@@ -63,6 +64,12 @@ public class WrapperTester extends AndroidTestCase {
audioCodecs = mCore.getAudioCodecs();
Assert.assertEquals(audioCodecs.length, audioCodecsNb - 1);
}
+
+ //Test LinphoneFriend ref key
+ String key = "12";
+ LinphoneFriend friend = LinphoneCoreFactory.instance().createLinphoneFriend("sip:lala@test.linphone.org");
+ friend.setRefKey(key);
+ Assert.assertEquals(friend.getRefKey(),key);
}
@Override
diff --git a/res/layout-small/status.xml b/res/layout-small/status.xml
index 13203f9d0..c79638cbb 100644
--- a/res/layout-small/status.xml
+++ b/res/layout-small/status.xml
@@ -241,6 +241,19 @@
android:adjustViewBounds="true"
android:visibility="gone"
android:layout_alignParentRight="true" />
+
+
-
d MMM
EEEE MMM d HH:mm
HH:mm d MMM
HH:mm
linphone-mms-%s.jpg
-
+
Linphone
Linphone Service
Linphone
+ org.linphone
+ linphone contacts
+ vnd.android.cursor.item/org.linphone.profile
Linphone
Starting up
- Registered to %s
+ Registered to %s
Fails to register to %s
Linphone %s SIP (rfc 3261) compatible phone under GNU Public License V2
http://www.linphone.org\n\nInstructions\nhttp://www.linphone.org/m/help\n\n© 2011 Belledonne Communications
-
+
This assistant will help you to use a SIP account for your calls.
Create an account on linphone.org
I already have a linphone.org account
I already have a SIP account
Enter your linphone.org username and password
Enter your SIP account username, password and domain
-
- username
+ username
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 79551c89c..863a82ac8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -353,6 +353,7 @@
Sharing server
Remote provisioning
Delete
+ This contact will be deleted.
SIP address
Phone number
First name
diff --git a/res/xml/authenticator.xml b/res/xml/authenticator.xml
new file mode 100644
index 000000000..885948b88
--- /dev/null
+++ b/res/xml/authenticator.xml
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/res/xml/contacts.xml b/res/xml/contacts.xml
new file mode 100644
index 000000000..f05076c82
--- /dev/null
+++ b/res/xml/contacts.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/xml/syncadapter.xml b/res/xml/syncadapter.xml
new file mode 100644
index 000000000..0b7795d77
--- /dev/null
+++ b/res/xml/syncadapter.xml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/src/org/linphone/ChatListFragment.java b/src/org/linphone/ChatListFragment.java
index 4db0fe188..9b9dc6116 100644
--- a/src/org/linphone/ChatListFragment.java
+++ b/src/org/linphone/ChatListFragment.java
@@ -356,7 +356,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
Log.e("Chat view cannot parse address",e);
return view;
}
- LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, view.getContext().getContentResolver());
+ Contact lContact = ContactsManager.getInstance().findContactWithAddress(address);
String message = "";
if (useNativeAPI) {
@@ -393,14 +393,13 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
TextView sipUri = (TextView) view.findViewById(R.id.sipUri);
sipUri.setSelected(true); // For animation
-
- if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && address.getDisplayName() != null && LinphoneUtils.isSipAddress(address.getDisplayName())) {
- address.setDisplayName(LinphoneUtils.getUsernameFromAddress(address.getDisplayName()));
- } else if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(contact)) {
- contact = LinphoneUtils.getUsernameFromAddress(contact);
- }
-
- sipUri.setText(address.getDisplayName() == null ? contact : address.getDisplayName());
+
+ if (getResources().getBoolean(R.bool.only_display_username_if_unknown)) {
+ sipUri.setText(lContact == null ? address.getUserName() : lContact.getName());
+ } else {
+ sipUri.setText(lContact == null ? address.asStringUriOnly() : lContact.getName());
+ }
+
if (isDraft) {
view.findViewById(R.id.draft).setVisibility(View.VISIBLE);
}
diff --git a/src/org/linphone/Contact.java b/src/org/linphone/Contact.java
index 14d434808..4352bc21d 100644
--- a/src/org/linphone/Contact.java
+++ b/src/org/linphone/Contact.java
@@ -38,14 +38,15 @@ public class Contact implements Serializable {
private String name;
private transient Uri photoUri;
private transient Bitmap photo;
- private List numerosOrAddresses;
- private LinphoneFriend friend;
+ private List numbersOrAddresses;
+ private boolean hasFriends;
public Contact(String id, String name) {
super();
this.id = id;
this.name = name;
this.photoUri = null;
+ this.hasFriends = false;
}
public Contact(String id, String name, Uri photo) {
@@ -54,6 +55,7 @@ public class Contact implements Serializable {
this.name = name;
this.photoUri = photo;
this.photo = null;
+ this.hasFriends = false;
}
public Contact(String id, String name, Uri photo, Bitmap picture) {
@@ -62,14 +64,12 @@ public class Contact implements Serializable {
this.name = name;
this.photoUri = photo;
this.photo = picture;
+ this.hasFriends = false;
}
-
- public void setFriend(LinphoneFriend friend) {
- this.friend = friend;
- }
-
- public LinphoneFriend getFriend() {
- return friend;
+
+
+ public boolean hasFriends() {
+ return hasFriends;
}
public String getID() {
@@ -88,14 +88,20 @@ public class Contact implements Serializable {
return photo;
}
- public List getNumerosOrAddresses() {
- if (numerosOrAddresses == null)
- numerosOrAddresses = new ArrayList();
- return numerosOrAddresses;
+ public List getNumbersOrAddresses() {
+ if (numbersOrAddresses == null)
+ numbersOrAddresses = new ArrayList();
+ return numbersOrAddresses;
}
public void refresh(ContentResolver cr) {
- this.numerosOrAddresses = Compatibility.extractContactNumbersAndAddresses(id, cr);
+ this.numbersOrAddresses = Compatibility.extractContactNumbersAndAddresses(id, cr);
+ for(LinphoneFriend friend : LinphoneManager.getLc().getFriendList()) {
+ if (friend.getRefKey().equals(id)) {
+ hasFriends = true;
+ this.numbersOrAddresses.add(friend.getAddress().asStringUriOnly());
+ }
+ }
this.name = Compatibility.refreshContactName(cr, id);
}
}
diff --git a/src/org/linphone/ContactFragment.java b/src/org/linphone/ContactFragment.java
index 8de8ef76a..c6dc5e025 100644
--- a/src/org/linphone/ContactFragment.java
+++ b/src/org/linphone/ContactFragment.java
@@ -27,7 +27,9 @@ import org.linphone.mediastream.Log;
import org.linphone.ui.AvatarWithShadow;
import android.annotation.SuppressLint;
+import android.app.AlertDialog;
import android.content.ContentProviderOperation;
+import android.content.DialogInterface;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.ContactsContract;
@@ -118,11 +120,12 @@ public class ContactFragment extends Fragment implements OnClickListener {
}
TextView contactName = (TextView) view.findViewById(R.id.contactName);
- contactName.setText(contact.getName());
+ contactName.setText(contact.getName());
+
TableLayout controls = (TableLayout) view.findViewById(R.id.controls);
controls.removeAllViews();
- for (String numberOrAddress : contact.getNumerosOrAddresses()) {
+ for (String numberOrAddress : contact.getNumbersOrAddresses()) {
View v = inflater.inflate(R.layout.contact_control_row, null);
String displayednumberOrAddress = numberOrAddress;
@@ -168,7 +171,7 @@ public class ContactFragment extends Fragment implements OnClickListener {
friend.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- if (LinphoneActivity.instance().newFriend(contact, finalNumberOrAddress)) {
+ if (ContactsManager.getInstance().createNewFriend(contact, finalNumberOrAddress)) {
displayContact(ContactFragment.this.inflater, ContactFragment.this.view);
}
}
@@ -178,7 +181,7 @@ public class ContactFragment extends Fragment implements OnClickListener {
friend.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- if (LinphoneActivity.instance().removeFriend(contact, finalNumberOrAddress)) {
+ if (ContactsManager.getInstance().removeFriend(finalNumberOrAddress)) {
displayContact(ContactFragment.this.inflater, ContactFragment.this.view);
}
}
@@ -221,9 +224,17 @@ public class ContactFragment extends Fragment implements OnClickListener {
if (id == R.id.editContact) {
LinphoneActivity.instance().editContact(contact);
} else if (id == R.id.deleteContact) {
- deleteExistingContact();
- LinphoneActivity.instance().removeContactFromLists(contact);
- LinphoneActivity.instance().displayContacts(false);
+ AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());
+ alertDialog.setMessage(getString(R.string.delete_contact_dialog));
+ alertDialog.setPositiveButton(getString(R.string.button_ok),new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ deleteExistingContact();
+ ContactsManager.getInstance().removeContactFromLists(getActivity().getContentResolver(),contact);
+ LinphoneActivity.instance().displayContacts(false);
+ }
+ });
+ alertDialog.setNegativeButton(getString(R.string.button_cancel),null);
+ alertDialog.show();
}
}
@@ -239,6 +250,7 @@ public class ContactFragment extends Fragment implements OnClickListener {
try {
getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+ ContactsManager.getInstance().removeAllFriends(contact);
} catch (Exception e) {
Log.w(e.getMessage() + ":" + e.getStackTrace());
}
diff --git a/src/org/linphone/ContactHelper.java b/src/org/linphone/ContactHelper.java
deleted file mode 100644
index eb33caa98..000000000
--- a/src/org/linphone/ContactHelper.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
-ContactHelper.java
-Copyright (C) 2011 Belledonne Communications, Grenoble, France
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-package org.linphone;
-
-import org.linphone.core.LinphoneAddress;
-import org.linphone.core.LinphoneCore;
-import org.linphone.core.LinphoneProxyConfig;
-import org.linphone.mediastream.Version;
-
-import android.annotation.SuppressLint;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract.Contacts;
-import android.text.TextUtils;
-
-public final class ContactHelper {
- private String username;
- private String domain;
- private ContentResolver resolver;
-
- private Uri foundPhotoUri;
- public Uri getUri() {
- return foundPhotoUri;
- }
-
- private String displayName;
- public String getDisplayName() {
- return displayName;
- }
-
- private LinphoneAddress address;
- public ContactHelper(LinphoneAddress address, ContentResolver resolver) {
- username = address.getUserName();
- domain = address.getDomain();
- this.resolver = resolver;
- this.address = address;
- }
-
- public boolean query() {
- boolean succeeded = queryContact();
- if (succeeded && !TextUtils.isEmpty(displayName)) {
- address.setDisplayName(displayName);
- }
- return succeeded;
- }
-
- public static Intent prepareEditContactIntent(int id) {
- Intent intent = new Intent(Intent.ACTION_EDIT, Contacts.CONTENT_URI);
- Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
- intent.setData(contactUri);
-
- return intent;
- }
-
- public static boolean testPhotoUri(Cursor c) {
- if (c == null) return false;
- if (!c.moveToNext()) {
- return false;
- }
- byte[] data = c.getBlob(0);
- if (data == null) {
- // TODO: simplify all this stuff
- // which is here only to check that the
- // photoUri really points to some data.
- // Not retrieving the data now would be better.
- return false;
- }
- return true;
- }
-
- public static boolean testPhotoUriAndCloseCursor(Cursor c) {
- boolean valid = testPhotoUri(c);
- if (c != null) c.close();
- return valid;
- }
-
- public static boolean testPhotoUri(ContentResolver resolver, Uri photoUriToTest, String photoCol) {
- Cursor cursor = resolver.query(photoUriToTest, new String[]{photoCol}, null, null, null);
- return testPhotoUriAndCloseCursor(cursor);
- }
-
- private void checkPhotosUris(ContentResolver resolver, Cursor c, String idCol, String nameCol) {
- displayName = c.getString(c.getColumnIndex(nameCol));
-
- long id = c.getLong(c.getColumnIndex(idCol));
- Uri contactUri = ContentUris.withAppendedId(android.provider.ContactsContract.Contacts.CONTENT_URI, id);
- Uri photoUri = Uri.withAppendedPath(contactUri, android.provider.ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
-
- if (photoUri != null) {
- String[] projection = { android.provider.ContactsContract.CommonDataKinds.Photo.PHOTO };
- Cursor photoCursor = resolver.query(photoUri, projection, null, null, null);
-
- boolean isPhotoValid = testPhotoUriAndCloseCursor(photoCursor);
- if (isPhotoValid) {
- foundPhotoUri = photoUri;
- }
- }
- }
-
- private boolean checkSIPQueryResult(Cursor c, String columnSip) {
- boolean contactFound = false;
-
- if (c != null) {
- while (!contactFound && c.moveToNext()) {
- String contact = c.getString(c.getColumnIndex(columnSip));
- if (contact.equals(username + "@" + domain) || contact.equals(username)) {
- contactFound = true;
- checkPhotosUris(resolver, c, android.provider.ContactsContract.Data.CONTACT_ID, android.provider.ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
- } else {
- String normalizedUsername = null;
- LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
- if (lc != null) {
- LinphoneProxyConfig lpc = lc.getDefaultProxyConfig();
- if (lpc != null) {
- if (contact.contains("@")) {
- normalizedUsername = lpc.normalizePhoneNumber(contact.split("@")[0]);
- } else {
- normalizedUsername = lpc.normalizePhoneNumber(contact);
- }
- }
- }
- if (normalizedUsername != null && normalizedUsername.equals(username)) {
- contactFound = true;
- checkPhotosUris(resolver, c, android.provider.ContactsContract.Data.CONTACT_ID, android.provider.ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
- }
- }
- }
- c.close();
- }
-
- return contactFound;
- }
-
- private boolean checkPhoneQueryResult(Cursor c, String columnPhone) {
- boolean contactFound = false;
-
- if (c != null) {
- while (!contactFound && c.moveToNext()) {
- String contact = c.getString(c.getColumnIndex(columnPhone));
- if (contact.equals(username)) {
- contactFound = true;
- checkPhotosUris(resolver, c, android.provider.ContactsContract.PhoneLookup._ID, android.provider.ContactsContract.PhoneLookup.DISPLAY_NAME);
- } else {
- String normalizedUsername = null;
- LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
- if (lc != null) {
- LinphoneProxyConfig lpc = lc.getDefaultProxyConfig();
- if (lpc != null) {
- normalizedUsername = lpc.normalizePhoneNumber(contact);
- }
- }
- if (normalizedUsername != null && normalizedUsername.equals(username)) {
- contactFound = true;
- checkPhotosUris(resolver, c, android.provider.ContactsContract.PhoneLookup._ID, android.provider.ContactsContract.PhoneLookup.DISPLAY_NAME);
- }
- }
- }
- c.close();
- }
-
- return contactFound;
- }
-
- @SuppressLint("InlinedApi")
- private final boolean queryContact() {
- boolean contactFound = false;
-
- Uri uri = android.provider.ContactsContract.Data.CONTENT_URI;
- String[] projection = { android.provider.ContactsContract.Data.CONTACT_ID, android.provider.ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, android.provider.ContactsContract.CommonDataKinds.Im.DATA };
-
- String selection = new StringBuilder()
- .append(android.provider.ContactsContract.Data.MIMETYPE)
- .append(" = '")
- .append(android.provider.ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
- .append("' AND lower(")
- .append(android.provider.ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL)
- .append(") = 'sip'").toString();
-
- Cursor c = resolver.query(uri, projection, selection, null, null);
- contactFound = checkSIPQueryResult(c, android.provider.ContactsContract.CommonDataKinds.Im.DATA);
- if (contactFound) {
- return true;
- }
-
- if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
- selection = new StringBuilder()
- .append(android.provider.ContactsContract.Data.MIMETYPE)
- .append(" = '")
- .append(android.provider.ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
- .append("'")
- .toString();
- c = resolver.query(uri, projection, selection, null, null);
- contactFound = checkSIPQueryResult(c, android.provider.ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
- if (contactFound) {
- return true;
- }
- }
-
- Uri lookupUri = Uri.withAppendedPath(android.provider.ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(username));
- projection = new String[] {
- android.provider.ContactsContract.PhoneLookup._ID,
- android.provider.ContactsContract.PhoneLookup.NUMBER,
- android.provider.ContactsContract.PhoneLookup.DISPLAY_NAME };
- c = resolver.query(lookupUri, projection, null, null, null);
- contactFound = checkPhoneQueryResult(c, android.provider.ContactsContract.PhoneLookup.NUMBER);
-
- return contactFound;
- }
-}
\ No newline at end of file
diff --git a/src/org/linphone/ContactsFragment.java b/src/org/linphone/ContactsFragment.java
index a013fceb7..aa886801a 100644
--- a/src/org/linphone/ContactsFragment.java
+++ b/src/org/linphone/ContactsFragment.java
@@ -22,6 +22,7 @@ import java.util.List;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.PresenceActivityType;
+import org.linphone.mediastream.Log;
import android.annotation.SuppressLint;
import android.database.Cursor;
@@ -127,7 +128,7 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
searchContacts(searchField.getText().toString());
}
});
-
+
return view;
}
@@ -169,7 +170,6 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
changeContactsAdapter();
return;
}
-
changeContactsToggle();
if (searchCursor != null) {
@@ -177,11 +177,11 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
}
if (onlyDisplayLinphoneContacts) {
- searchCursor = Compatibility.getSIPContactsCursor(getActivity().getContentResolver(), search);
+ searchCursor = Compatibility.getSIPContactsCursor(getActivity().getContentResolver(), search, ContactsManager.getInstance().getContactsId());
indexer = new AlphabetIndexer(searchCursor, Compatibility.getCursorDisplayNameColumnIndex(searchCursor), " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
contactsList.setAdapter(new ContactsListAdapter(null, searchCursor));
} else {
- searchCursor = Compatibility.getContactsCursor(getActivity().getContentResolver(), search);
+ searchCursor = Compatibility.getContactsCursor(getActivity().getContentResolver(), search, ContactsManager.getInstance().getContactsId());
indexer = new AlphabetIndexer(searchCursor, Compatibility.getCursorDisplayNameColumnIndex(searchCursor), " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
contactsList.setAdapter(new ContactsListAdapter(null, searchCursor));
}
@@ -194,8 +194,8 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
searchCursor.close();
}
- Cursor allContactsCursor = LinphoneActivity.instance().getAllContactsCursor();
- Cursor sipContactsCursor = LinphoneActivity.instance().getSIPContactsCursor();
+ Cursor allContactsCursor = ContactsManager.getInstance().getAllContactsCursor();
+ Cursor sipContactsCursor = ContactsManager.getInstance().getSIPContactsCursor();
noSipContact.setVisibility(View.GONE);
noContact.setVisibility(View.GONE);
@@ -207,7 +207,7 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
contactsList.setVisibility(View.GONE);
} else {
indexer = new AlphabetIndexer(sipContactsCursor, Compatibility.getCursorDisplayNameColumnIndex(sipContactsCursor), " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
- contactsList.setAdapter(new ContactsListAdapter(LinphoneActivity.instance().getSIPContacts(), sipContactsCursor));
+ contactsList.setAdapter(new ContactsListAdapter(ContactsManager.getInstance().getSIPContacts(), sipContactsCursor));
}
} else {
if (allContactsCursor.getCount() == 0) {
@@ -215,10 +215,10 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
contactsList.setVisibility(View.GONE);
} else {
indexer = new AlphabetIndexer(allContactsCursor, Compatibility.getCursorDisplayNameColumnIndex(allContactsCursor), " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
- contactsList.setAdapter(new ContactsListAdapter(LinphoneActivity.instance().getAllContacts(), allContactsCursor));
+ contactsList.setAdapter(new ContactsListAdapter(ContactsManager.getInstance().getAllContacts(), allContactsCursor));
}
}
- LinphoneActivity.instance().setLinphoneContactsPrefered(onlyDisplayLinphoneContacts);
+ ContactsManager.getInstance().setLinphoneContactsPrefered(onlyDisplayLinphoneContacts);
}
private void changeContactsToggle() {
@@ -255,7 +255,7 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACTS);
- onlyDisplayLinphoneContacts = LinphoneActivity.instance().isLinphoneContactsPrefered();
+ onlyDisplayLinphoneContacts = ContactsManager.getInstance().isLinphoneContactsPrefered();
if (getResources().getBoolean(R.bool.show_statusbar_only_on_dialer)) {
LinphoneActivity.instance().hideStatusBar();
@@ -350,10 +350,10 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
}
ImageView friendStatus = (ImageView) view.findViewById(R.id.friendStatus);
- LinphoneFriend friend = contact.getFriend();
- if (!LinphoneActivity.instance().isContactPresenceDisabled() && friend != null) {
+ LinphoneFriend[] friends = LinphoneManager.getLc().getFriendList();
+ if (!ContactsManager.getInstance().isContactPresenceDisabled() && friends != null) {
friendStatus.setVisibility(View.VISIBLE);
- PresenceActivityType presenceActivity = friend.getPresenceModel().getActivity().getType();
+ PresenceActivityType presenceActivity = friends[0].getPresenceModel().getActivity().getType();
if (presenceActivity == PresenceActivityType.Online) {
friendStatus.setImageResource(R.drawable.led_connected);
} else if (presenceActivity == PresenceActivityType.Busy) {
diff --git a/src/org/linphone/ContactsManager.java b/src/org/linphone/ContactsManager.java
new file mode 100644
index 000000000..6e5ecbbdc
--- /dev/null
+++ b/src/org/linphone/ContactsManager.java
@@ -0,0 +1,515 @@
+package org.linphone;
+/*
+CallManager.java
+Copyright (C) 2015 Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+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 org.linphone.compatibility.Compatibility;
+import org.linphone.core.LinphoneAddress;
+import org.linphone.core.LinphoneCoreException;
+import org.linphone.core.LinphoneCoreFactory;
+import org.linphone.core.LinphoneFriend;
+import org.linphone.mediastream.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ContactsManager {
+ private static ContactsManager instance;
+ private List contactList, sipContactList;
+ private Cursor contactCursor, sipContactCursor;
+ private Account mAccount;
+ private boolean preferLinphoneContacts = false, isContactPresenceDisabled = true;
+ private ContentResolver contentResolver;
+ private Context context;
+
+ private ContactsManager() {}
+
+ public static final synchronized ContactsManager getInstance() {
+ if (instance == null) instance = new ContactsManager();
+ return instance;
+ }
+
+ public List getAllContacts() {
+ return contactList;
+ }
+
+ public List getSIPContacts() {
+ return sipContactList;
+ }
+
+ public Cursor getAllContactsCursor() {
+ return contactCursor;
+ }
+
+ public Cursor getSIPContactsCursor() {
+ return sipContactCursor;
+ }
+
+ public void setLinphoneContactsPrefered(boolean isPrefered) {
+ preferLinphoneContacts = isPrefered;
+ }
+
+ public boolean isLinphoneContactsPrefered() {
+ return preferLinphoneContacts;
+ }
+
+ public boolean isContactPresenceDisabled() {
+ return isContactPresenceDisabled;
+ }
+
+ public void initializeSyncAccount(Context context, ContentResolver contentResolver) {
+ this.context = context;
+ this.contentResolver = contentResolver;
+ Account newAccount = new Account(context.getString(R.string.sync_account_name), context.getString(R.string.sync_account_type));
+ AccountManager accountManager = (AccountManager) context.getSystemService(context.ACCOUNT_SERVICE);
+ accountManager.addAccountExplicitly(newAccount, null, null);
+ mAccount = newAccount;
+ }
+
+ public String getDisplayName(String firstName, String lastName) {
+ String displayName = null;
+ if (firstName.length() > 0 && lastName.length() > 0)
+ displayName = firstName + " " + lastName;
+ else if (firstName.length() > 0)
+ displayName = firstName;
+ else if (lastName.length() > 0)
+ displayName = lastName.toString();
+ return displayName;
+ }
+
+ //Contacts
+ public void createNewContact(ArrayList ops, String firstName, String lastName){
+ int contactID = 0;
+
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
+ .withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
+ .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
+ .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
+ .build()
+ );
+
+ if (getDisplayName(firstName, lastName) != null) {
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, contactID)
+ .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, firstName)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, lastName)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, getDisplayName(firstName,lastName))
+ .build()
+ );
+ }
+ }
+
+ public void updateExistingContact(ArrayList ops, Contact contact, String firstName, String lastName) {
+ if (getDisplayName(firstName, lastName) != null) {
+ String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'" ;
+ String[] args = new String[] { String.valueOf(contact.getID()) };
+
+ ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
+ .withSelection(select, args)
+ .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, firstName)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, lastName)
+ .build()
+ );
+ }
+ }
+
+//Manage Linphone Friend if we cannot use Sip address
+ public boolean createNewFriend(Contact contact, String sipUri) {
+ if (!sipUri.startsWith("sip:")) {
+ sipUri = "sip:" + sipUri;
+ }
+
+ LinphoneFriend friend = LinphoneCoreFactory.instance().createLinphoneFriend(sipUri);
+ if(friend != null) {
+ friend.edit();
+ friend.setRefKey(contact.getID());
+ friend.done();
+ try {
+ LinphoneManager.getLc().addFriend(friend);
+ return true;
+ } catch (LinphoneCoreException e) {
+ e.printStackTrace();
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public void updateFriend(String oldSipUri, String newSipUri) {
+ if (!newSipUri.startsWith("sip:")) {
+ newSipUri = "sip:" + newSipUri;
+ }
+
+ if (!oldSipUri.startsWith("sip:")) {
+ oldSipUri = "sip:" + oldSipUri;
+ }
+
+ LinphoneFriend friend = LinphoneManager.getLc().findFriendByAddress(oldSipUri);
+ if(friend != null) {
+ friend.edit();
+ try {
+ friend.setAddress(LinphoneCoreFactory.instance().createLinphoneAddress(newSipUri));
+ } catch (LinphoneCoreException e) {
+ e.printStackTrace();
+ }
+ friend.done();
+ }
+ }
+
+ public boolean removeFriend(String sipUri) {
+ if (!sipUri.startsWith("sip:")) {
+ sipUri = "sip:" + sipUri;
+ }
+
+ LinphoneFriend friend = LinphoneManager.getLc().findFriendByAddress(sipUri);
+ if (friend != null) {
+ LinphoneManager.getLc().removeFriend(friend);
+ return true;
+ }
+ return false;
+ }
+
+ public void removeAllFriends(Contact contact) {
+ for(LinphoneFriend friend : LinphoneManager.getLc().getFriendList()){
+ if(friend.getRefKey().equals(contact.getID())) {
+ LinphoneManager.getLc().removeFriend(friend);
+ }
+ }
+ }
+
+ public Contact findContactWithDisplayName(String displayName) {
+ String[] projection = { ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME };
+ String selection = new StringBuilder()
+ .append(ContactsContract.Data.DISPLAY_NAME)
+ .append(" = ?").toString();
+
+ Cursor c = contentResolver.query(ContactsContract.Data.CONTENT_URI,projection,selection,
+ new String[]{displayName}, null);
+ if (c != null) {
+ if (c.moveToFirst()) {
+ Contact contact = Compatibility.getContact(contentResolver,c,c.getPosition());
+ c.close();
+
+ if(contact != null) {
+ return contact;
+ } else {
+ return null;
+ }
+ }
+ c.close();
+ }
+ return null;
+ }
+
+ public List getContactsId(){
+ List ids = new ArrayList();
+ if(LinphoneManager.getLc().getFriendList() == null) return null;
+ for(LinphoneFriend friend : LinphoneManager.getLc().getFriendList()) {
+ if(!ids.contains(friend.getRefKey())){
+ ids.add(friend.getRefKey());
+ }
+ }
+
+ return ids;
+ }
+//End linphone Friend
+
+ public boolean removeContactTagIsNeeded(Contact contact){
+ contact.refresh(contentResolver);
+ boolean onlyNumbers = true;
+ for(String address: contact.getNumbersOrAddresses()){
+ if(LinphoneUtils.isSipAddress(address)){
+ onlyNumbers = false;
+ }
+ }
+
+ return onlyNumbers;
+ }
+
+ public void removeLinphoneContactTag(Contact contact){
+ ArrayList ops = new ArrayList();
+ String select = ContactsContract.RawContacts._ID + " = ?";
+ String[] args = new String[] { findRawLinphoneContactID(contact.getID()) };
+
+
+ ops.add(ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI)
+ .withSelection(select, args)
+ .build()
+ );
+
+ try {
+ contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
+ } catch (Exception e) {
+ Log.w(e.getMessage() + ":" + e.getStackTrace());
+ }
+ }
+
+ public Contact findContactWithAddress(LinphoneAddress address){
+ for(Contact contact : contactList){
+ if(contact.getNumbersOrAddresses().contains(address.asStringUriOnly()) || contact.getNumbersOrAddresses().contains(address.getUserName())){
+ return contact;
+ }
+ }
+ return null;
+ }
+
+ public void removeContactFromLists(ContentResolver contentResolver, Contact contact) {
+ for (Contact c : contactList) {
+ if (c != null && c.getID().equals(contact.getID())) {
+ contactList.remove(c);
+ contactCursor = Compatibility.getContactsCursor(contentResolver,getContactsId());
+ break;
+ }
+ }
+
+ for (Contact c : sipContactList) {
+ if (c != null && c.getID().equals(contact.getID())) {
+ sipContactList.remove(c);
+ sipContactCursor = Compatibility.getSIPContactsCursor(contentResolver,getContactsId());
+ break;
+ }
+ }
+ }
+
+ public boolean isContactHasAddress(Contact contact, String address){
+ if(contact != null) {
+ contact.refresh(contentResolver);
+ if (contact.getNumbersOrAddresses().contains("sip:" + address)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ public String findRawContactID(ContentResolver cr, String contactID) {
+ Cursor c = cr.query(ContactsContract.RawContacts.CONTENT_URI,
+ new String[]{ContactsContract.RawContacts._ID},
+ ContactsContract.RawContacts.CONTACT_ID + "=?",
+ new String[]{contactID}, null);
+ if (c != null) {
+ String result = null;
+ if (c.moveToFirst()) {
+ result = c.getString(c.getColumnIndex(ContactsContract.RawContacts._ID));
+ }
+
+ c.close();
+ return result;
+ }
+ return null;
+ }
+
+ public String findRawLinphoneContactID(String contactID) {
+ String result = null;
+ String[] projection = { ContactsContract.RawContacts._ID };
+
+ String selection = ContactsContract.RawContacts.CONTACT_ID + "=? AND "
+ + ContactsContract.RawContacts.ACCOUNT_TYPE + "=? ";
+
+ Cursor c = contentResolver.query(ContactsContract.RawContacts.CONTENT_URI, projection,
+ selection, new String[]{contactID, "org.linphone"}, null);
+ if (c != null) {
+ if (c.moveToFirst()) {
+ result = c.getString(c.getColumnIndex(ContactsContract.RawContacts._ID));
+ }
+ }
+ c.close();
+ return result;
+ }
+
+ //Migrate old IM contacts into SIP addresses or linphoneFriends
+ public void migrateContacts() {
+ Cursor oldContacts = Compatibility.getImContactsCursor(contentResolver);
+ ArrayList ops = new ArrayList();
+
+ if(oldContacts != null){
+ for (int i = 0; i < oldContacts.getCount(); i++) {
+ Contact contact = Compatibility.getContact(contentResolver, oldContacts, i);
+ for (String address : Compatibility.extractContactImAddresses(contact.getID(), contentResolver)) {
+ if (LinphoneUtils.isSipAddress(address)) {
+ if (address.startsWith("sip:")) {
+ address = address.substring(4);
+ }
+
+ //Add new sip address
+ Compatibility.addSipAddressToContact(context, ops, address, findRawContactID(contentResolver, contact.getID()));
+ try {
+ contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ ops.clear();
+
+ contact.refresh(contentResolver);
+
+ //If address sip is correctly add, remove the im address
+ if(contact.getNumbersOrAddresses().contains(address)){
+ Compatibility.deleteImAddressFromContact(ops, address, contact.getID());
+ try {
+ contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ ops.clear();
+ } else {
+ //Add linphone friend instead
+ if(createNewFriend(contact, address)) {
+ contact.refresh(contentResolver);
+
+ //Remove IM address
+ Compatibility.deleteImAddressFromContact(ops, address, contact.getID());
+ try {
+ contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
+ } catch (Exception e) {
+ e.printStackTrace();
+
+ }
+ }
+ }
+ }
+ ops.clear();
+ }
+ }
+ oldContacts.close();
+ }
+
+ }
+
+ public synchronized void prepareContactsInBackground() {
+ if (contactCursor != null) {
+ contactCursor.close();
+ }
+ if (sipContactCursor != null) {
+ sipContactCursor.close();
+ }
+
+ contactCursor = Compatibility.getContactsCursor(contentResolver, getContactsId());
+ sipContactCursor = Compatibility.getSIPContactsCursor(contentResolver, getContactsId());
+
+ Thread sipContactsHandler = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ if(sipContactCursor.getCount() > 0) {
+ for (int i = 0; i < sipContactCursor.getCount(); i++) {
+ Contact contact = Compatibility.getContact(contentResolver, sipContactCursor, i);
+ if (contact == null)
+ continue;
+
+ contact.refresh(contentResolver);
+ //Add tag to Linphone contact if it not existed
+ if(!isContactHasLinphoneTag(contact,contentResolver)){
+ Compatibility.createLinphoneContactTag(context,contentResolver,contact,
+ findRawContactID(contentResolver, String.valueOf(contact.getID())));
+ }
+
+ sipContactList.add(contact);
+ }
+ }
+ if (contactCursor != null) {
+ for (int i = 0; i < contactCursor.getCount(); i++) {
+ Contact contact = Compatibility.getContact(contentResolver, contactCursor, i);
+
+ if (contact == null)
+ continue;
+
+ //Remove linphone contact tag if the contact has no sip address
+ if(removeContactTagIsNeeded(contact) && isContactHasLinphoneTag(contact,contentResolver)){
+ removeLinphoneContactTag(contact);
+ }
+
+ for (Contact c : sipContactList) {
+ if (c != null && c.getID().equals(contact.getID())) {
+ contact = c;
+ break;
+ }
+ }
+ contactList.add(contact);
+ }
+ }
+ }
+ });
+
+ contactList = new ArrayList();
+ sipContactList = new ArrayList();
+
+ sipContactsHandler.start();
+ }
+
+ public static String queryAddressOrNumber(ContentResolver resolver, Uri contactUri) {
+ // Phone Numbers
+ String[] projection = new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER};
+ Cursor c = resolver.query(contactUri, projection, null, null, null);
+ if (c != null) {
+ while (c.moveToNext()) {
+ int numberIndex = c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
+ String number = c.getString(numberIndex);
+ c.close();
+ return number;
+ }
+ }
+
+ // SIP addresses
+ projection = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS};
+ c = resolver.query(contactUri, projection, null, null, null);
+ if (c != null) {
+ while (c.moveToNext()) {
+ int numberIndex = c.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
+ String address = c.getString(numberIndex);
+ c.close();
+ return address;
+ }
+ }
+
+ c.close();
+ return null;
+ }
+
+ boolean isContactHasLinphoneTag(Contact contact, ContentResolver cr) {
+ String select = ContactsContract.Data.CONTACT_ID + " = ?";
+ String[] args = new String[] { contact.getID() };
+
+ String[] projection = new String[] {ContactsContract.Data.MIMETYPE };
+
+ Cursor cursor = cr.query(ContactsContract.Data.CONTENT_URI, projection, select, args, null);
+
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ if(cursor.getString(cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)).equals("vnd.android.cursor.item/org.linphone.profile")){
+ cursor.close();
+ return true;
+ }
+ }
+ }
+ cursor.close();
+ return false;
+ }
+
+}
diff --git a/src/org/linphone/DialerFragment.java b/src/org/linphone/DialerFragment.java
index 279ee6c61..07ed122c8 100644
--- a/src/org/linphone/DialerFragment.java
+++ b/src/org/linphone/DialerFragment.java
@@ -198,8 +198,14 @@ public class DialerFragment extends Fragment {
} else if (scheme.startsWith("call") || scheme.startsWith("sip")) {
mAddress.setText(intent.getData().getSchemeSpecificPart());
} else {
- Log.e("Unknown scheme: ",scheme);
- mAddress.setText(intent.getData().getSchemeSpecificPart());
+ Uri contactUri = intent.getData();
+ String address = ContactsManager.getInstance().queryAddressOrNumber(getActivity().getContentResolver(),contactUri);
+ if(address != null) {
+ mAddress.setText(address);
+ } else {
+ Log.e("Unknown scheme: ", scheme);
+ mAddress.setText(intent.getData().getSchemeSpecificPart());
+ }
}
mAddress.clearDisplayedName();
diff --git a/src/org/linphone/EditContactFragment.java b/src/org/linphone/EditContactFragment.java
index 1eb37daa9..edb2bb77e 100644
--- a/src/org/linphone/EditContactFragment.java
+++ b/src/org/linphone/EditContactFragment.java
@@ -13,7 +13,6 @@ import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.ContactsContract;
-import android.provider.ContactsContract.RawContacts;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.InputType;
@@ -41,7 +40,8 @@ public class EditContactFragment extends Fragment {
private ArrayList ops;
private int firstSipAddressIndex = -1;
private String newSipOrNumberToAdd;
-
+ private ContactsManager contactsManager;
+
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.inflater = inflater;
@@ -58,6 +58,8 @@ public class EditContactFragment extends Fragment {
isNewContact = true;
}
}
+
+ contactsManager = ContactsManager.getInstance();
view = inflater.inflate(R.layout.edit_contact, container, false);
@@ -87,9 +89,9 @@ public class EditContactFragment extends Fragment {
return;
}
}
- createNewContact();
+ contactsManager.createNewContact(ops, firstName.getText().toString(), lastName.getText().toString());
} else {
- updateExistingContact();
+ contactsManager.updateExistingContact(ops, contact, firstName.getText().toString(), lastName.getText().toString());
}
for (NewOrUpdatedNumberOrAddress numberOrAddress : numbersAndAddresses) {
@@ -97,12 +99,13 @@ public class EditContactFragment extends Fragment {
}
try {
- getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
- LinphoneActivity.instance().prepareContactsInBackground();
+ getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+ addLinphoneFriendIfNeeded();
+ contactsManager.prepareContactsInBackground();
} catch (Exception e) {
e.printStackTrace();
}
-
+
getFragmentManager().popBackStackImmediate();
}
});
@@ -156,7 +159,7 @@ public class EditContactFragment extends Fragment {
public void afterTextChanged(Editable s) {
}
});
-
+
if (!isNewContact) {
String fn = findContactFirstName(String.valueOf(contactID));
String ln = findContactLastName(String.valueOf(contactID));
@@ -201,7 +204,7 @@ public class EditContactFragment extends Fragment {
numbersAndAddresses = new ArrayList();
if (contact != null) {
- for (String numberOrAddress : contact.getNumerosOrAddresses()) {
+ for (String numberOrAddress : contact.getNumbersOrAddresses()) {
View view = displayNumberOrAddress(controls, numberOrAddress);
if (view != null)
controls.addView(view);
@@ -288,6 +291,7 @@ public class EditContactFragment extends Fragment {
nounoa.delete();
numbersAndAddresses.remove(nounoa);
view.setVisibility(View.GONE);
+
}
});
return view;
@@ -354,66 +358,6 @@ public class EditContactFragment extends Fragment {
}
}
- private void createNewContact() {
- contactID = 0;
-
- ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
- .withValue(RawContacts.ACCOUNT_TYPE, null)
- .withValue(RawContacts.ACCOUNT_NAME, null).build());
-
- if (getDisplayName() != null) {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, contactID)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, firstName.getText().toString())
- .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, lastName.getText().toString())
- .build()
- );
- }
- }
-
- private void updateExistingContact() {
- if (getDisplayName() != null) {
- String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'" ;
- String[] args = new String[] { String.valueOf(contactID) };
-
- ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
- .withSelection(select, args)
- .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, firstName.getText().toString())
- .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, lastName.getText().toString())
- .build()
- );
- }
- }
-
- private String getDisplayName() {
- String displayName = null;
- if (firstName.getText().length() > 0 && lastName.getText().length() > 0)
- displayName = firstName.getText().toString() + " " + lastName.getText().toString();
- else if (firstName.getText().length() > 0)
- displayName = firstName.getText().toString();
- else if (lastName.getText().length() > 0)
- displayName = lastName.getText().toString();
- return displayName;
- }
-
- private String findRawContactID(String contactID) {
- Cursor c = getActivity().getContentResolver().query(RawContacts.CONTENT_URI,
- new String[]{RawContacts._ID},
- RawContacts.CONTACT_ID + "=?",
- new String[]{contactID}, null);
- if (c != null) {
- String result = null;
- if (c.moveToFirst()) {
- result = c.getString(c.getColumnIndex(RawContacts._ID));
- }
- c.close();
- return result;
- }
- return null;
- }
-
private String findContactFirstName(String contactID) {
Cursor c = getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI,
new String[]{ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME},
@@ -445,6 +389,26 @@ public class EditContactFragment extends Fragment {
}
return null;
}
+
+ private void addLinphoneFriendIfNeeded(){
+ for (NewOrUpdatedNumberOrAddress numberOrAddress : numbersAndAddresses) {
+ if(numberOrAddress.newNumberOrAddress != null && numberOrAddress.isSipAddress && !contactsManager.isContactHasAddress(contact, numberOrAddress.newNumberOrAddress)) {
+ if(isNewContact){
+ Contact c = contactsManager.findContactWithDisplayName(ContactsManager.getInstance().getDisplayName(firstName.getText().toString(), lastName.getText().toString()));
+ if (c != null) {
+ contactsManager.createNewFriend(c, numberOrAddress.newNumberOrAddress);
+ }
+ } else {
+ if (numberOrAddress.oldNumberOrAddress == null) {
+ contactsManager.createNewFriend(contact, numberOrAddress.newNumberOrAddress);
+ } else {
+ if(contact.hasFriends())
+ contactsManager.updateFriend(numberOrAddress.oldNumberOrAddress, numberOrAddress.newNumberOrAddress);
+ }
+ }
+ }
+ }
+ }
class NewOrUpdatedNumberOrAddress {
private String oldNumberOrAddress;
@@ -494,7 +458,12 @@ public class EditContactFragment extends Fragment {
public void delete() {
if (isSipAddress) {
- Compatibility.deleteSipAddressFromContact(ops, oldNumberOrAddress, String.valueOf(contactID));
+ if(contact.hasFriends()) {
+ ContactsManager.getInstance().removeFriend(oldNumberOrAddress);
+ } else {
+ Compatibility.deleteSipAddressFromContact(ops, oldNumberOrAddress, String.valueOf(contactID));
+ }
+ Compatibility.deleteLinphoneContactTag(ops, oldNumberOrAddress, contactsManager.findRawLinphoneContactID(String.valueOf(contactID)));
} else {
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "' AND "
@@ -521,24 +490,25 @@ public class EditContactFragment extends Fragment {
newNumberOrAddress = newNumberOrAddress + "@" + getResources().getString(R.string.default_domain);
Compatibility.addSipAddressToContact(getActivity(), ops, newNumberOrAddress);
} else {
- ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, newNumberOrAddress)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM)
- .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, getString(R.string.addressbook_label))
+ .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, getString(R.string.addressbook_label))
.build()
);
}
} else {
- String rawContactId = findRawContactID(String.valueOf(contactID));
-
+ String rawContactId = contactsManager.findRawContactID(getActivity().getContentResolver(),String.valueOf(contactID));
if (isSipAddress) {
if (newNumberOrAddress.startsWith("sip:"))
newNumberOrAddress = newNumberOrAddress.substring(4);
if(!newNumberOrAddress.contains("@"))
newNumberOrAddress = newNumberOrAddress + "@" + getResources().getString(R.string.default_domain);
- Compatibility.addSipAddressToContact(getActivity(), ops, newNumberOrAddress, rawContactId);
+
+ Compatibility.addSipAddressToContact(getActivity(), ops, newNumberOrAddress, rawContactId);
+ Compatibility.addLinphoneContactTag(getActivity(), ops, newNumberOrAddress, contactsManager.findRawLinphoneContactID(String.valueOf(contactID)));
} else {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
@@ -563,6 +533,7 @@ public class EditContactFragment extends Fragment {
if(!newNumberOrAddress.contains("@"))
newNumberOrAddress = newNumberOrAddress + "@" + getResources().getString(R.string.default_domain);
Compatibility.updateSipAddressForContact(ops, oldNumberOrAddress, newNumberOrAddress, String.valueOf(contactID));
+ Compatibility.updateLinphoneContactTag(getActivity(), ops, newNumberOrAddress, oldNumberOrAddress, contactsManager.findRawLinphoneContactID(String.valueOf(contactID)));
} else {
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "' AND "
@@ -578,4 +549,4 @@ public class EditContactFragment extends Fragment {
}
}
}
-}
+}
\ No newline at end of file
diff --git a/src/org/linphone/HistoryDetailFragment.java b/src/org/linphone/HistoryDetailFragment.java
index e82c67093..7d0eae6d8 100644
--- a/src/org/linphone/HistoryDetailFragment.java
+++ b/src/org/linphone/HistoryDetailFragment.java
@@ -108,16 +108,16 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener {
time.setText(callTime == null ? "" : callTime);
date.setText(timestampToHumanDate(callDate));
-
+
LinphoneAddress lAddress;
try {
lAddress = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri);
- Uri pictureUri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, view.getContext().getContentResolver());
- if(pictureUri != null)
- LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture.getView(), Uri.parse(pictureUri.toString()), R.drawable.unknown_small);
- String displayName = lAddress.getDisplayName();
- if (displayName != null) {
+ Contact contact = ContactsManager.getInstance().findContactWithAddress(lAddress);
+ if (contact != null) {
+ LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture.getView(),contact.getPhotoUri(), R.drawable.unknown_small);
view.findViewById(R.id.addContactRow).setVisibility(View.GONE);
+ } else {
+ LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture.getView(),null ,R.drawable.unknown_small);
}
} catch (LinphoneCoreException e) {
e.printStackTrace();
diff --git a/src/org/linphone/HistoryFragment.java b/src/org/linphone/HistoryFragment.java
index e6f6c1066..6f7c2ee97 100644
--- a/src/org/linphone/HistoryFragment.java
+++ b/src/org/linphone/HistoryFragment.java
@@ -178,15 +178,16 @@ public class HistoryFragment extends Fragment implements OnClickListener, OnChil
address = log.getTo();
}
- LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, getActivity().getContentResolver());
- displayName = address.getDisplayName();
+ Contact contact = ContactsManager.getInstance().findContactWithAddress(address);
String sipUri = address.asStringUriOnly();
- if (displayName == null) {
+ if (contact == null) {
if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(sipUri)) {
- displayName = LinphoneUtils.getUsernameFromAddress(sipUri);
+ displayName = address.getUserName();
} else {
displayName = sipUri;
}
+ } else {
+ displayName = contact.getName();
}
return displayName;
@@ -389,8 +390,7 @@ public class HistoryFragment extends Fragment implements OnClickListener, OnChil
address = log.getTo();
callDirection.setImageBitmap(outgoingCall);
}
-
- LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, view.getContext().getContentResolver());
+
String sipUri = address.asStringUriOnly();
dateAndTime.setText(log.getStartDate() + " " + log.getCallDuration());
view.setTag(sipUri);
@@ -455,8 +455,7 @@ public class HistoryFragment extends Fragment implements OnClickListener, OnChil
} else {
address = log.getTo();
}
-
- LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, view.getContext().getContentResolver());
+
String displayName = getCorrespondentDisplayName(log);
String sipUri = address.asStringUriOnly();
contact.setText(displayName + " (" + getChildrenCount(groupPosition) + ")");
diff --git a/src/org/linphone/HistorySimpleFragment.java b/src/org/linphone/HistorySimpleFragment.java
index 0827efd1d..266a84d78 100644
--- a/src/org/linphone/HistorySimpleFragment.java
+++ b/src/org/linphone/HistorySimpleFragment.java
@@ -391,22 +391,25 @@ public class HistorySimpleFragment extends Fragment implements OnClickListener,
address = log.getTo();
callDirection.setImageBitmap(outgoingCall);
}
-
- LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, view.getContext().getContentResolver());
- String displayName = address.getDisplayName();
- String sipUri = address.asStringUriOnly();
+
+ Contact c = ContactsManager.getInstance().findContactWithAddress(address);
+ String displayName = null;
+ final String sipUri = address.asStringUriOnly();
+ if(c != null){
+ displayName = c.getName();
+ }
if (displayName == null) {
if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(sipUri)) {
- contact.setText(LinphoneUtils.getUsernameFromAddress(sipUri));
+ contact.setText(address.getUserName());
} else {
contact.setText(sipUri);
}
} else {
if (getResources().getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(address.getDisplayName())) {
- contact.setText(LinphoneUtils.getUsernameFromAddress(address.getDisplayName()));
- } else {
contact.setText(displayName);
+ } else {
+ contact.setText(sipUri);
}
}
view.setTag(sipUri);
@@ -421,7 +424,7 @@ public class HistorySimpleFragment extends Fragment implements OnClickListener,
@Override
public void onClick(View v) {
if (LinphoneActivity.isInstanciated()) {
- LinphoneActivity.instance().displayHistoryDetail(address.asStringUriOnly(), log);
+ LinphoneActivity.instance().displayHistoryDetail(sipUri, log);
}
}
});
diff --git a/src/org/linphone/InCallActivity.java b/src/org/linphone/InCallActivity.java
index a4be92910..052cfd18c 100644
--- a/src/org/linphone/InCallActivity.java
+++ b/src/org/linphone/InCallActivity.java
@@ -1299,8 +1299,12 @@ public class InCallActivity extends FragmentActivity implements OnClickListener
// Image Row
LinearLayout imageView = (LinearLayout) inflater.inflate(R.layout.active_call_image_row, container, false);
- Uri pictureUri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, imageView.getContext().getContentResolver());
- displayOrHideContactPicture(imageView, pictureUri, false);
+ Contact contact = ContactsManager.getInstance().findContactWithAddress(lAddress);
+ if(contact != null) {
+ displayOrHideContactPicture(imageView, contact.getPhotoUri(), false);
+ } else {
+ displayOrHideContactPicture(imageView, null, false);
+ }
callsList.addView(imageView);
callView.setTag(imageView);
@@ -1321,18 +1325,16 @@ public class InCallActivity extends FragmentActivity implements OnClickListener
private void setContactName(LinearLayout callView, LinphoneAddress lAddress, String sipUri, Resources resources) {
TextView contact = (TextView) callView.findViewById(R.id.contactNameOrNumber);
-
- LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, callView.getContext().getContentResolver());
- String displayName = lAddress.getDisplayName();
- if (displayName == null) {
+ Contact lContact = ContactsManager.getInstance().findContactWithAddress(lAddress);
+ if (lContact == null) {
if (resources.getBoolean(R.bool.only_display_username_if_unknown) && LinphoneUtils.isSipAddress(sipUri)) {
- contact.setText(LinphoneUtils.getUsernameFromAddress(sipUri));
+ contact.setText(lAddress.getUserName());
} else {
contact.setText(sipUri);
}
} else {
- contact.setText(displayName);
+ contact.setText(lContact.getName());
}
}
diff --git a/src/org/linphone/IncomingCallActivity.java b/src/org/linphone/IncomingCallActivity.java
index a3fc3de46..fa04b0ad9 100644
--- a/src/org/linphone/IncomingCallActivity.java
+++ b/src/org/linphone/IncomingCallActivity.java
@@ -124,11 +124,11 @@ public class IncomingCallActivity extends Activity implements LinphoneSliderTrig
}
LinphoneAddress address = mCall.getRemoteAddress();
// May be greatly sped up using a drawable cache
- Uri uri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, getContentResolver());
- LinphoneUtils.setImagePictureFromUri(this, mPictureView.getView(), uri, R.drawable.unknown_small);
+ Contact contact = ContactsManager.getInstance().findContactWithAddress(address);
+ LinphoneUtils.setImagePictureFromUri(this, mPictureView.getView(), contact != null ? contact.getPhotoUri() : null, R.drawable.unknown_small);
// To be done after findUriPictureOfContactAndSetDisplayName called
- mNameView.setText(address.getDisplayName());
+ mNameView.setText(contact != null ? contact.getName() : "");
if (getResources().getBoolean(R.bool.only_display_username_if_unknown)) {
mNumberView.setText(address.getUserName());
} else {
diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java
index 9f91481ea..271e435b7 100644
--- a/src/org/linphone/LinphoneActivity.java
+++ b/src/org/linphone/LinphoneActivity.java
@@ -42,7 +42,6 @@ import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListenerBase;
-import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.mediastream.Log;
import org.linphone.setup.RemoteProvisioningLoginActivity;
@@ -55,11 +54,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.database.Cursor;
+import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
+import android.provider.ContactsContract;
import android.support.v4.app.Fragment;
import android.support.v4.app.Fragment.SavedState;
import android.support.v4.app.FragmentActivity;
@@ -76,7 +75,6 @@ import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
-import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
@@ -105,9 +103,7 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
private List fragmentsHistory;
private Fragment dialerFragment, messageListFragment, friendStatusListenerFragment;
private SavedState dialerSavedState;
- private boolean preferLinphoneContacts = false, isAnimationDisabled = false, isContactPresenceDisabled = true;
- private List contactList, sipContactList;
- private Cursor contactCursor, sipContactCursor;
+ private boolean isAnimationDisabled = false, preferLinphoneContacts = false;
private OrientationEventListener mOrientationHelper;
private LinphoneCoreListenerBase mListener;
@@ -153,6 +149,13 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
}
}
+ ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver());
+
+ if(!LinphonePreferences.instance().isContactsMigrationDone()){
+ ContactsManager.getInstance().migrateContacts();
+ LinphonePreferences.instance().contactsMigrationDone();
+ }
+
setContentView(R.layout.main);
instance = this;
fragmentsHistory = new ArrayList();
@@ -248,6 +251,7 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
updateAnimationsState();
}
+
private void initButtons() {
menu = (LinearLayout) findViewById(R.id.menu);
mark = (LinearLayout) findViewById(R.id.mark);
@@ -400,17 +404,12 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
private void updateAnimationsState() {
isAnimationDisabled = getResources().getBoolean(R.bool.disable_animations) || !LinphonePreferences.instance().areAnimationsEnabled();
- isContactPresenceDisabled = !getResources().getBoolean(R.bool.enable_linphone_friends);
}
public boolean isAnimationDisabled() {
return isAnimationDisabled;
}
- public boolean isContactPresenceDisabled() {
- return isContactPresenceDisabled;
- }
-
private void changeFragment(Fragment newFragment, FragmentsAvailable newFragmentType, boolean withoutAnimation) {
if (statusFragment != null) {
statusFragment.closeStatusBar();
@@ -517,10 +516,10 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
Log.e("Cannot display history details",e);
return;
}
- Uri uri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, getContentResolver());
+ Contact c = ContactsManager.getInstance().findContactWithAddress(lAddress);
- String displayName = lAddress.getDisplayName();
- String pictureUri = uri == null ? null : uri.toString();
+ String displayName = c != null ? c.getName() : null;
+ String pictureUri = c != null && c.getPhotoUri() != null ? c.getPhotoUri().toString() : null;
String status;
if (log.getDirection() == CallDirection.Outgoing) {
@@ -610,9 +609,9 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
Log.e("Cannot display chat",e);
return;
}
- Uri uri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(lAddress, getContentResolver());
- String displayName = lAddress.getDisplayName();
- String pictureUri = uri == null ? null : uri.toString();
+ Contact contact = ContactsManager.getInstance().findContactWithAddress(lAddress);
+ String displayName = contact != null ? contact.getName() : null;
+ String pictureUri = contact != null && contact.getPhotoUri() != null ? contact.getPhotoUri().toString() : null;
if (currentFragment == FragmentsAvailable.CHATLIST || currentFragment == FragmentsAvailable.CHAT) {
if (isTablet()) {
@@ -629,16 +628,16 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
}
changeCurrentFragment(FragmentsAvailable.CHAT, extras);
}
- } else {
- Intent intent = new Intent(this, ChatActivity.class);
- intent.putExtra("SipUri", sipUri);
- if (lAddress.getDisplayName() != null) {
- intent.putExtra("DisplayName", displayName);
- intent.putExtra("PictureUri", pictureUri);
- }
- startOrientationSensor();
- startActivityForResult(intent, CHAT_ACTIVITY);
}
+ } else {
+ Intent intent = new Intent(this, ChatActivity.class);
+ intent.putExtra("SipUri", sipUri);
+ if (contact != null) {
+ intent.putExtra("DisplayName", contact.getName());
+ intent.putExtra("PictureUri", contact.getPhotoUri());
+ }
+ startOrientationSensor();
+ startActivityForResult(intent, CHAT_ACTIVITY);
}
LinphoneService.instance().resetMessageNotifCount();
@@ -906,7 +905,6 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
}
private int mAlwaysChangingPhoneAngle = -1;
- private AcceptNewFriendDialog acceptNewFriendDialog;
private class LocalOrientationEventListener extends OrientationEventListener {
public LocalOrientationEventListener(Context context) {
@@ -945,202 +943,6 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
}
}
- public void showPreferenceErrorDialog(String message) {
-
- }
-
- public List getAllContacts() {
- return contactList;
- }
-
- public List getSIPContacts() {
- return sipContactList;
- }
-
- public Cursor getAllContactsCursor() {
- return contactCursor;
- }
-
- public Cursor getSIPContactsCursor() {
- return sipContactCursor;
- }
-
- public void setLinphoneContactsPrefered(boolean isPrefered) {
- preferLinphoneContacts = isPrefered;
- }
-
- public boolean isLinphoneContactsPrefered() {
- return preferLinphoneContacts;
- }
-
- public void onNewSubscriptionRequestReceived(LinphoneFriend friend,
- String sipUri) {
- if (isContactPresenceDisabled) {
- return;
- }
-
- sipUri = sipUri.replace("<", "").replace(">", "");
- if (LinphonePreferences.instance().shouldAutomaticallyAcceptFriendsRequests()) {
- Contact contact = findContactWithSipAddress(sipUri);
- if (contact != null) {
- friend.enableSubscribes(true);
- try {
- LinphoneManager.getLc().addFriend(friend);
- contact.setFriend(friend);
- } catch (LinphoneCoreException e) {
- e.printStackTrace();
- }
- }
- } else {
- Contact contact = findContactWithSipAddress(sipUri);
- if (contact != null) {
- FragmentManager fm = getSupportFragmentManager();
- acceptNewFriendDialog = new AcceptNewFriendDialog(contact, sipUri);
- acceptNewFriendDialog.show(fm, "New Friend Request Dialog");
- }
- }
- }
-
- private Contact findContactWithSipAddress(String sipUri) {
- if (!sipUri.startsWith("sip:")) {
- sipUri = "sip:" + sipUri;
- }
-
- for (Contact contact : sipContactList) {
- for (String addr : contact.getNumerosOrAddresses()) {
- if (addr.equals(sipUri)) {
- return contact;
- }
- }
- }
- return null;
- }
-
- public void onNotifyPresenceReceived(LinphoneFriend friend) {
- if (!isContactPresenceDisabled && currentFragment == FragmentsAvailable.CONTACTS && friendStatusListenerFragment != null) {
- ((ContactsFragment) friendStatusListenerFragment).invalidate();
- }
- }
-
- public boolean newFriend(Contact contact, String sipUri) {
- LinphoneFriend friend = LinphoneCoreFactory.instance().createLinphoneFriend(sipUri);
- friend.enableSubscribes(true);
- friend.setIncSubscribePolicy(LinphoneFriend.SubscribePolicy.SPAccept);
- try {
- LinphoneManager.getLc().addFriend(friend);
- contact.setFriend(friend);
- return true;
- } catch (LinphoneCoreException e) {
- e.printStackTrace();
- }
- return false;
- }
-
- private void acceptNewFriend(Contact contact, String sipUri, boolean accepted) {
- acceptNewFriendDialog.dismissAllowingStateLoss();
- if (accepted) {
- newFriend(contact, sipUri);
- }
- }
-
- public boolean removeFriend(Contact contact, String sipUri) {
- LinphoneFriend friend = LinphoneManager.getLc().findFriendByAddress(sipUri);
- if (friend != null) {
- friend.enableSubscribes(false);
- LinphoneManager.getLc().removeFriend(friend);
- contact.setFriend(null);
- return true;
- }
- return false;
- }
-
- private void searchFriendAndAddToContact(Contact contact) {
- if (contact == null || contact.getNumerosOrAddresses() == null) {
- return;
- }
-
- for (String sipUri : contact.getNumerosOrAddresses()) {
- if (LinphoneUtils.isSipAddress(sipUri)) {
- LinphoneFriend friend = LinphoneManager.getLc().findFriendByAddress(sipUri);
- if (friend != null) {
- friend.enableSubscribes(true);
- friend.setIncSubscribePolicy(LinphoneFriend.SubscribePolicy.SPAccept);
- contact.setFriend(friend);
- break;
- }
- }
- }
- }
-
- public void removeContactFromLists(Contact contact) {
- for (Contact c : contactList) {
- if (c != null && c.getID().equals(contact.getID())) {
- contactList.remove(c);
- contactCursor = Compatibility.getContactsCursor(getContentResolver());
- break;
- }
- }
-
- for (Contact c : sipContactList) {
- if (c != null && c.getID().equals(contact.getID())) {
- sipContactList.remove(c);
- sipContactCursor = Compatibility.getSIPContactsCursor(getContentResolver());
- break;
- }
- }
- }
-
- public synchronized void prepareContactsInBackground() {
- if (contactCursor != null) {
- contactCursor.close();
- }
- if (sipContactCursor != null) {
- sipContactCursor.close();
- }
-
- contactCursor = Compatibility.getContactsCursor(getContentResolver());
- sipContactCursor = Compatibility.getSIPContactsCursor(getContentResolver());
-
- Thread sipContactsHandler = new Thread(new Runnable() {
- @Override
- public void run() {
- if(sipContactCursor != null) {
- for (int i = 0; i < sipContactCursor.getCount(); i++) {
- Contact contact = Compatibility.getContact(getContentResolver(), sipContactCursor, i);
- if (contact == null)
- continue;
-
- contact.refresh(getContentResolver());
- if (!isContactPresenceDisabled) {
- searchFriendAndAddToContact(contact);
- }
- sipContactList.add(contact);
- }
- }
- if(contactCursor != null) {
- for (int i = 0; i < contactCursor.getCount(); i++) {
- Contact contact = Compatibility.getContact(getContentResolver(), contactCursor, i);
- if (contact == null)
- continue;
-
- for (Contact c : sipContactList) {
- if (c != null && c.getID().equals(contact.getID())) {
- contact = c;
- break;
- }
- }
- contactList.add(contact);
- }
- }
- }
- });
-
- contactList = new ArrayList();
- sipContactList = new ArrayList();
-
- sipContactsHandler.start();
- }
-
private void initInCallMenuLayout(boolean callTransfer) {
selectMenu(FragmentsAvailable.DIALER);
if (dialerFragment != null) {
@@ -1195,6 +997,7 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
extras.putSerializable("Contact", contact);
changeCurrentFragment(FragmentsAvailable.EDIT_CONTACT, extras);
}
+
}
public void editContact(Contact contact, String sipAddress)
@@ -1252,7 +1055,7 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
}
- prepareContactsInBackground();
+ ContactsManager.getInstance().prepareContactsInBackground();
updateMissedChatCount();
@@ -1396,42 +1199,6 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
}
return super.onKeyDown(keyCode, event);
}
-
- @SuppressLint("ValidFragment")
- class AcceptNewFriendDialog extends DialogFragment {
- private Contact contact;
- private String sipUri;
-
- public AcceptNewFriendDialog(Contact c, String a) {
- contact = c;
- sipUri = a;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.new_friend_request_dialog, container);
-
- getDialog().setTitle(R.string.linphone_friend_new_request_title);
-
- Button yes = (Button) view.findViewById(R.id.yes);
- yes.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- acceptNewFriend(contact, sipUri, true);
- }
- });
-
- Button no = (Button) view.findViewById(R.id.no);
- no.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- acceptNewFriend(contact, sipUri, false);
- }
- });
-
- return view;
- }
- }
}
interface ContactPicked {
diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java
index 3baa6ff0b..bf82c470e 100644
--- a/src/org/linphone/LinphoneManager.java
+++ b/src/org/linphone/LinphoneManager.java
@@ -715,9 +715,13 @@ public class LinphoneManager implements LinphoneCoreListener {
}
try {
- LinphoneUtils.findUriPictureOfContactAndSetDisplayName(from, mServiceContext.getContentResolver());
+ Contact contact = ContactsManager.getInstance().findContactWithAddress(from);
if (!mServiceContext.getResources().getBoolean(R.bool.disable_chat__message_notification)) {
- LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), from.getDisplayName(), textMessage);
+ if(contact != null) {
+ LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), contact.getName(), textMessage);
+ } else {
+ LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), from.getUserName(), textMessage);
+ }
}
} catch (Exception e) { }
}
diff --git a/src/org/linphone/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java
index 17fed12c1..bdb89344a 100644
--- a/src/org/linphone/LinphonePreferences.java
+++ b/src/org/linphone/LinphonePreferences.java
@@ -1143,4 +1143,12 @@ public class LinphonePreferences {
public void setCodecBitrateLimit(int bitrate) {
getConfig().setInt("audio", "codec_bitrate_limit", bitrate);
}
+
+ public void contactsMigrationDone(){
+ getConfig().setBool("app", "contacts_migration_done",true);
+ }
+
+ public boolean isContactsMigrationDone(){
+ return getConfig().getBool("app", "contacts_migration_done",false);
+ }
}
diff --git a/src/org/linphone/LinphoneService.java b/src/org/linphone/LinphoneService.java
index 034867c38..f88dae86d 100644
--- a/src/org/linphone/LinphoneService.java
+++ b/src/org/linphone/LinphoneService.java
@@ -45,6 +45,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
@@ -52,6 +53,7 @@ import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
+import android.provider.ContactsContract;
import android.provider.MediaStore;
/**
@@ -235,10 +237,12 @@ public final class LinphoneService extends Service {
mStartForeground = getClass().getMethod("startForeground", mStartFgSign);
mStopForeground = getClass().getMethod("stopForeground", mStopFgSign);
} catch (NoSuchMethodException e) {
- Log.e(e, "Couldn't find startGoreground or stopForeground");
+ Log.e(e, "Couldn't find startForeground or stopForeground");
}
}
+ this.getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, mObserver);
+
startForegroundCompat(NOTIF_ID, mNotif);
if (!mTestDelayElapsed) {
@@ -259,6 +263,15 @@ public final class LinphoneService extends Service {
, mkeepAlivePendingIntent);
}
+ private ContentObserver mObserver = new ContentObserver(new Handler()) {
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ }
+
+ };
+
private enum IncallIconState {INCALL, PAUSE, VIDEO, IDLE}
private IncallIconState mCurrentIncallIconState = IncallIconState.IDLE;
private synchronized void setIncallIcon(IncallIconState state) {
@@ -299,7 +312,8 @@ public final class LinphoneService extends Service {
LinphoneAddress address = LinphoneCoreFactory.instance().createLinphoneAddress(userName,domain,null);
address.setDisplayName(displayName);
- Uri pictureUri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(address, getContentResolver());
+ Contact contact = ContactsManager.getInstance().findContactWithAddress(address);
+ Uri pictureUri = contact != null ? contact.getPhotoUri() : null;
Bitmap bm = null;
try {
bm = MediaStore.Images.Media.getBitmap(getContentResolver(), pictureUri);
@@ -376,7 +390,8 @@ public final class LinphoneService extends Service {
Uri pictureUri;
try {
- pictureUri = LinphoneUtils.findUriPictureOfContactAndSetDisplayName(LinphoneCoreFactory.instance().createLinphoneAddress(fromSipUri), getContentResolver());
+ Contact contact = ContactsManager.getInstance().findContactWithAddress(LinphoneCoreFactory.instance().createLinphoneAddress(fromSipUri));
+ pictureUri = contact.getPhotoUri();
} catch (LinphoneCoreException e1) {
Log.e("Cannot parse from address",e1);
pictureUri=null;
@@ -548,6 +563,7 @@ public final class LinphoneService extends Service {
mNM.cancel(MESSAGE_NOTIF_ID);
((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).cancel(mkeepAlivePendingIntent);
+ getContentResolver().unregisterContentObserver(mObserver);
super.onDestroy();
}
diff --git a/src/org/linphone/LinphoneUtils.java b/src/org/linphone/LinphoneUtils.java
index c82eb5d8c..177d11534 100644
--- a/src/org/linphone/LinphoneUtils.java
+++ b/src/org/linphone/LinphoneUtils.java
@@ -97,14 +97,14 @@ public final class LinphoneUtils {
public static boolean isStrictSipAddress(String numberOrAddress) {
return isSipAddress(numberOrAddress) && numberOrAddress.startsWith("sip:");
}
-
+
public static String getUsernameFromAddress(String address) {
if (address.contains("sip:"))
address = address.replace("sip:", "");
-
+
if (address.contains("@"))
address = address.split("@")[0];
-
+
return address;
}
@@ -137,20 +137,9 @@ public final class LinphoneUtils {
}
- /**
- * @param contact sip uri
- * @return url/uri of the resource
- */
-// public static Uri findUriPictureOfContactAndSetDisplayName(LinphoneAddress address, ContentResolver resolver) {
-// return Compatibility.findUriPictureOfContactAndSetDisplayName(address, resolver);
-// }
-
- public static Uri findUriPictureOfContactAndSetDisplayName(LinphoneAddress address, ContentResolver resolver) {
- ContactHelper helper = new ContactHelper(address, resolver);
- helper.query();
- return helper.getUri();
- }
+
+
public static Bitmap downloadBitmap(Uri uri) {
URL url;
InputStream is = null;
diff --git a/src/org/linphone/PreferencesMigrator.java b/src/org/linphone/PreferencesMigrator.java
index 85d4c0f4b..f6cae93c4 100644
--- a/src/org/linphone/PreferencesMigrator.java
+++ b/src/org/linphone/PreferencesMigrator.java
@@ -19,7 +19,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences.AccountBuilder;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException;
@@ -28,6 +27,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Resources;
+
import android.preference.PreferenceManager;
/**
@@ -120,7 +120,7 @@ public class PreferencesMigrator {
doAccountMigration(i, i == getPrefInt(R.string.pref_default_account_key, 0));
}
}
-
+
private void doAccountMigration(int index, boolean isDefaultAccount) {
String key = index == 0 ? "" : String.valueOf(index);
@@ -163,7 +163,7 @@ public class PreferencesMigrator {
}
}
}
-
+
private void deleteAllOldPreferences() {
Editor editor = mOldPrefs.edit();
editor.clear();
diff --git a/src/org/linphone/StatusFragment.java b/src/org/linphone/StatusFragment.java
index 7a3862829..e6f997b2c 100644
--- a/src/org/linphone/StatusFragment.java
+++ b/src/org/linphone/StatusFragment.java
@@ -134,7 +134,6 @@ public class StatusFragment extends Fragment {
});
}
// setMiniLedsForEachAccount();
- populateSliderContent();
populateSliderContent();
sliderContentAccounts.invalidate();
} catch (IllegalStateException ise) {}
@@ -163,11 +162,10 @@ public class StatusFragment extends Fragment {
}
};
-
+
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.addListener(mListener);
-
LinphoneProxyConfig lpc = lc.getDefaultProxyConfig();
if (lpc != null) {
mListener.registrationState(lc, lpc, lpc.getState(), null);
diff --git a/src/org/linphone/compatibility/ApiElevenPlus.java b/src/org/linphone/compatibility/ApiElevenPlus.java
index d252c3985..1fc9b8409 100644
--- a/src/org/linphone/compatibility/ApiElevenPlus.java
+++ b/src/org/linphone/compatibility/ApiElevenPlus.java
@@ -18,7 +18,7 @@ import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents.Insert;
@@ -144,9 +144,8 @@ public class ApiElevenPlus {
ArrayList data = new ArrayList();
ContentValues sipAddressRow = new ContentValues();
- sipAddressRow.put(Contacts.Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
- sipAddressRow.put(Im.DATA, sipUri);
- sipAddressRow.put(Im.CUSTOM_PROTOCOL,"Sip");
+ sipAddressRow.put(Contacts.Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE);
+ sipAddressRow.put(SipAddress.SIP_ADDRESS, sipUri);
data.add(sipAddressRow);
intent.putParcelableArrayListExtra(Insert.DATA, data);
@@ -160,10 +159,8 @@ public class ApiElevenPlus {
ArrayList data = new ArrayList();
ContentValues sipAddressRow = new ContentValues();
- sipAddressRow.put(Contacts.Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
- sipAddressRow.put(Im.DATA, sipUri);
- sipAddressRow.put(Im.CUSTOM_PROTOCOL,"Sip");
- data.add(sipAddressRow);
+ sipAddressRow.put(Contacts.Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE);
+ sipAddressRow.put(SipAddress.SIP_ADDRESS, sipUri);
data.add(sipAddressRow);
intent.putParcelableArrayListExtra(Insert.DATA, data);
diff --git a/src/org/linphone/compatibility/ApiFivePlus.java b/src/org/linphone/compatibility/ApiFivePlus.java
index 02a86c282..d538428eb 100644
--- a/src/org/linphone/compatibility/ApiFivePlus.java
+++ b/src/org/linphone/compatibility/ApiFivePlus.java
@@ -33,6 +33,7 @@ import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.text.ClipboardManager;
+import android.text.TextUtils;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -111,7 +112,7 @@ public class ApiFivePlus {
c.close();
}
- // SIP addresses
+ // IM addresses
String selection = new StringBuilder()
.append(Data.CONTACT_ID).append(" = ? AND ")
.append(Data.MIMETYPE).append(" = '")
@@ -132,38 +133,49 @@ public class ApiFivePlus {
return list;
}
- public static Cursor getContactsCursor(ContentResolver cr) {
+ public static Cursor getContactsCursor(ContentResolver cr, List 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')";
+ + "' 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 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);
}
- public static Cursor getSIPContactsCursor(ContentResolver cr) {
- String req = null;
- req = Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
- + "' AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip'";
-
- 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 + "'";
-
+ 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 = Data.DISPLAY_NAME + " IS NOT NULL AND (" + select + ")";
+ 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) {
@@ -206,7 +218,7 @@ public class ApiFivePlus {
String name = getContactDisplayName(cursor);
Uri photo = getContactPictureUri(id);
InputStream input = getContactPictureInputStream(cr, id);
-
+
Contact contact;
if (input == null) {
contact = new Contact(id, name);
@@ -246,7 +258,7 @@ public class ApiFivePlus {
Cursor cursor = getSIPContactCursor(cr, sipUri);
Contact contact = getContact(cr, cursor, 0);
- if (contact != null && contact.getNumerosOrAddresses().contains(sipUri)) {
+ if (contact != null && contact.getNumbersOrAddresses().contains(sipUri)) {
address.setDisplayName(contact.getName());
cursor.close();
return contact.getPhotoUri();
diff --git a/src/org/linphone/compatibility/ApiNinePlus.java b/src/org/linphone/compatibility/ApiNinePlus.java
index cd83f47ea..1a586b42a 100644
--- a/src/org/linphone/compatibility/ApiNinePlus.java
+++ b/src/org/linphone/compatibility/ApiNinePlus.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import org.linphone.Contact;
+import org.linphone.LinphoneUtils;
import org.linphone.R;
import org.linphone.core.LinphoneAddress;
@@ -18,6 +19,7 @@ import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
+import android.text.TextUtils;
/*
ApiNinePlus.java
@@ -42,52 +44,48 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
@TargetApi(9)
public class ApiNinePlus {
-
+
public static void addSipAddressToContact(Context context, ArrayList 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.PROTOCOL, ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM)
- .withValue(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL,"Sip")
- .withValue(ContactsContract.CommonDataKinds.Im.LABEL, context.getString(R.string.addressbook_label))
- .build()
- );
+ 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 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.PROTOCOL, ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM)
- .withValue(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL,"Sip")
- .withValue(ContactsContract.CommonDataKinds.Im.LABEL, context.getString(R.string.addressbook_label))
+ 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 ops, String oldIm, String newIm, String contactID) {
- String select = ContactsContract.Data.CONTACT_ID + "=? AND "
- + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE + "' AND "
- + ContactsContract.CommonDataKinds.Im.DATA + "=? AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip'";
- String[] args = new String[] { String.valueOf(contactID), oldIm };
+ public static void updateSipAddressForContact(ArrayList 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.Im.CONTENT_ITEM_TYPE)
- .withValue(ContactsContract.CommonDataKinds.Im.DATA, newIm)
+ .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 ops, String oldIm, String contactID) {
- String select = ContactsContract.Data.CONTACT_ID + "=? AND "
- + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE + "' AND "
- + ContactsContract.CommonDataKinds.Im.DATA + "=? AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip'";
- String[] args = new String[] { String.valueOf(contactID), oldIm };
+ public static void deleteSipAddressFromContact(ArrayList 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)
@@ -99,7 +97,7 @@ public class ApiNinePlus {
List list = new ArrayList();
Uri uri = Data.CONTENT_URI;
- String[] projection = {ContactsContract.CommonDataKinds.Im.DATA};
+ String[] projection;
// Phone Numbers
Cursor c = cr.query(Phone.CONTENT_URI, new String[] { Phone.NUMBER }, Phone.CONTACT_ID + " = " + id, null, null);
@@ -110,28 +108,7 @@ public class ApiNinePlus {
}
c.close();
}
-
- // 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();
- projection = new String[] {ContactsContract.CommonDataKinds.Im.DATA};
- 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();
- }
-
+
// SIP addresses
String selection2 = new StringBuilder()
.append(Data.CONTACT_ID)
@@ -150,52 +127,56 @@ public class ApiNinePlus {
}
c.close();
}
-
+
return list;
}
- public static Cursor getContactsCursor(ContentResolver cr, String search) {
- String req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
- + "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL OR ("
- + Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
- + "' AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip'"
- + " AND " + ContactsContract.CommonDataKinds.Im.DATA + " IS NOT NULL"
- + ") OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ public static Cursor getContactsCursor(ContentResolver cr, String search, List 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) {
- String req = null;
- req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
- + "' AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip'"
- + " AND " + ContactsContract.CommonDataKinds.Im.DATA + " 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 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.Im.CONTENT_ITEM_TYPE
- + " AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip' AND "
- + android.provider.ContactsContract.CommonDataKinds.Im.DATA + " LIKE '" + id + "' "
- + " OR " + Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
- + " AND " + android.provider.ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " LIKE '" + id + "'";
+ 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();
@@ -203,7 +184,7 @@ public class ApiNinePlus {
Cursor cursor = getSIPContactCursor(cr, sipUri);
Contact contact = ApiFivePlus.getContact(cr, cursor, 0);
- if (contact != null && contact.getNumerosOrAddresses().contains(sipUri)) {
+ if (contact != null && contact.getNumbersOrAddresses().contains(sipUri)) {
address.setDisplayName(contact.getName());
cursor.close();
return contact.getPhotoUri();
@@ -212,4 +193,89 @@ public class ApiNinePlus {
cursor.close();
return null;
}
+
+ //Linphone Contacts Tag
+ public static void addLinphoneContactTag(Context context, ArrayList ops, String newAddress, String rawContactId){
+ if(rawContactId != null) {
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
+ .withValue(ContactsContract.Data.MIMETYPE, context.getString(R.string.sync_mimetype))
+ .withValue(ContactsContract.Data.DATA1, newAddress)
+ .withValue(ContactsContract.Data.DATA2, context.getString(R.string.app_name))
+ .withValue(ContactsContract.Data.DATA3, newAddress)
+ .build()
+ );
+ }
+ }
+ public static void updateLinphoneContactTag(Context context, ArrayList ops, String newAddress, String oldAddress, String rawContactId){
+ if(rawContactId != null) {
+ ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
+ .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.DATA1 + "=? ", new String[]{rawContactId, oldAddress})
+ .withValue(ContactsContract.Data.DATA1, newAddress)
+ .withValue(ContactsContract.Data.DATA2, context.getString(R.string.app_name))
+ .withValue(ContactsContract.Data.DATA3, newAddress)
+ .build());
+ }
+ }
+
+ public static void deleteLinphoneContactTag(ArrayList ops , String oldAddress, String rawContactId){
+ if(rawContactId != null) {
+ String select = ContactsContract.Data.RAW_CONTACT_ID + "=? AND "
+ + ContactsContract.Data.DATA1 + "= ?";
+ String[] args = new String[]{rawContactId, oldAddress};
+
+ ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
+ .withSelection(select, args)
+ .build());
+ }
+ }
+
+ public static void createLinphoneContactTag(Context context, ContentResolver contentResolver, Contact contact, String rawContactId){
+ ArrayList ops = new ArrayList();
+
+ if (contact != null) {
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
+ .withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
+ .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, context.getString(R.string.sync_account_type))
+ .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, context.getString(R.string.sync_account_name))
+ .build()
+ );
+
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+ .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getName())
+ .build()
+ );
+
+ List numbersOrAddresses = contact.getNumbersOrAddresses();
+ for (String numberOrAddress : numbersOrAddresses) {
+ if (LinphoneUtils.isSipAddress(numberOrAddress)) {
+ if (numberOrAddress.startsWith("sip:")){
+ numberOrAddress = numberOrAddress.substring(4);
+ }
+
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+ .withValue(ContactsContract.Data.MIMETYPE, context.getString(R.string.sync_mimetype))
+ .withValue(ContactsContract.Data.DATA1, numberOrAddress)
+ .withValue(ContactsContract.Data.DATA2, context.getString(R.string.app_name))
+ .withValue(ContactsContract.Data.DATA3, numberOrAddress)
+ .build()
+ );
+ }
+ }
+
+ ops.add(ContentProviderOperation.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI)
+ .withValue(ContactsContract.AggregationExceptions.TYPE, ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER)
+ .withValue(ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, rawContactId)
+ .withValueBackReference(ContactsContract.AggregationExceptions.RAW_CONTACT_ID2, 0).build());
+
+ try {
+ contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
}
diff --git a/src/org/linphone/compatibility/Compatibility.java b/src/org/linphone/compatibility/Compatibility.java
index 21ea8d89d..226ee1f9e 100644
--- a/src/org/linphone/compatibility/Compatibility.java
+++ b/src/org/linphone/compatibility/Compatibility.java
@@ -79,38 +79,50 @@ public class Compatibility {
return ApiFivePlus.extractContactNumbersAndAddresses(id, cr);
}
}
-
- public static Cursor getContactsCursor(ContentResolver cr) {
+
+ public static List extractContactImAddresses(String id, ContentResolver cr) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
- return ApiNinePlus.getContactsCursor(cr, null);
+ return ApiFivePlus.extractContactNumbersAndAddresses(id, cr);
} else {
- return ApiFivePlus.getContactsCursor(cr);
+ return null;
}
}
- public static Cursor getContactsCursor(ContentResolver cr, String search) {
+ public static Cursor getContactsCursor(ContentResolver cr, List contactsId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
- return ApiNinePlus.getContactsCursor(cr, search);
+ return ApiNinePlus.getContactsCursor(cr, null, contactsId);
} else {
- return ApiFivePlus.getContactsCursor(cr);
+ return ApiFivePlus.getContactsCursor(cr, contactsId);
}
}
- public static Cursor getSIPContactsCursor(ContentResolver cr) {
+ public static Cursor getContactsCursor(ContentResolver cr, String search, List contactsId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
- return ApiNinePlus.getSIPContactsCursor(cr, null);
+ return ApiNinePlus.getContactsCursor(cr, search, contactsId);
} else {
- return ApiFivePlus.getSIPContactsCursor(cr);
+ return ApiFivePlus.getContactsCursor(cr, contactsId);
+ }
+ }
+
+ public static Cursor getSIPContactsCursor(ContentResolver cr, List 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) {
+ public static Cursor getSIPContactsCursor(ContentResolver cr, String search, List contactsId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
- return ApiNinePlus.getSIPContactsCursor(cr, search);
+ return ApiNinePlus.getSIPContactsCursor(cr, search, contactsId);
} else {
- return ApiFivePlus.getSIPContactsCursor(cr);
+ 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)) {
@@ -261,7 +273,36 @@ public class Compatibility {
ApiFivePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
}
}
-
+
+ public static void deleteImAddressFromContact(ArrayList ops, String oldSipAddress, String contactID) {
+ ApiFivePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
+ }
+
+ //Linphone Contacts Tag
+ public static void addLinphoneContactTag(Context context, ArrayList ops, String newSipAddress, String rawContactId) {
+ if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
+ ApiNinePlus.addLinphoneContactTag(context, ops, newSipAddress, rawContactId);
+ }
+ }
+
+ public static void updateLinphoneContactTag(Context context, ArrayList ops, String newSipAddress, String oldSipAddress, String rawContactId) {
+ if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
+ ApiNinePlus.updateLinphoneContactTag(context, ops, newSipAddress, oldSipAddress, rawContactId);
+ }
+ }
+
+ public static void deleteLinphoneContactTag(ArrayList ops, String oldSipAddress, String rawContactId) {
+ if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
+ ApiNinePlus.deleteLinphoneContactTag(ops, oldSipAddress, rawContactId);
+ }
+ }
+
+ public static void createLinphoneContactTag(Context context, ContentResolver contentResolver, Contact contact, String rawContactId) {
+ if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
+ ApiNinePlus.createLinphoneContactTag(context, contentResolver, contact, rawContactId);
+ }
+ }
+ //End of Linphone Contact Tag
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, OnGlobalLayoutListener keyboardListener) {
if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
diff --git a/src/org/linphone/sync/AuthenticationService.java b/src/org/linphone/sync/AuthenticationService.java
new file mode 100644
index 000000000..aec317e82
--- /dev/null
+++ b/src/org/linphone/sync/AuthenticationService.java
@@ -0,0 +1,39 @@
+package org.linphone.sync;
+
+/*
+AuthenticationService.java
+Copyright (C) 2015 Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class AuthenticationService extends Service {
+
+ private Authenticator mAuthenticator;
+ @Override
+ public void onCreate() {
+ mAuthenticator = new Authenticator(this);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mAuthenticator.getIBinder();
+ }
+}
\ No newline at end of file
diff --git a/src/org/linphone/sync/Authenticator.java b/src/org/linphone/sync/Authenticator.java
new file mode 100644
index 000000000..30f3e8065
--- /dev/null
+++ b/src/org/linphone/sync/Authenticator.java
@@ -0,0 +1,85 @@
+package org.linphone.sync;
+
+/*
+Authenticator.java
+Copyright (C) 2015 Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.*;
+import android.content.Context;
+import android.os.Bundle;
+
+public class Authenticator extends AbstractAccountAuthenticator {
+
+ public Authenticator(Context context) {
+ super(context);
+ }
+
+ @Override
+ public Bundle editProperties(
+ AccountAuthenticatorResponse r, String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle addAccount(
+ AccountAuthenticatorResponse r,
+ String s,
+ String s2,
+ String[] strings,
+ Bundle bundle) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle confirmCredentials(
+ AccountAuthenticatorResponse r,
+ Account account,
+ Bundle bundle) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle getAuthToken(
+ AccountAuthenticatorResponse r,
+ Account account,
+ String s,
+ Bundle bundle) throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getAuthTokenLabel(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle updateCredentials(
+ AccountAuthenticatorResponse r,
+ Account account,
+ String s, Bundle bundle) throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle hasFeatures(
+ AccountAuthenticatorResponse r,
+ Account account, String[] strings) throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/src/org/linphone/sync/SyncAdapter.java b/src/org/linphone/sync/SyncAdapter.java
new file mode 100755
index 000000000..620adc861
--- /dev/null
+++ b/src/org/linphone/sync/SyncAdapter.java
@@ -0,0 +1,40 @@
+package org.linphone.sync;
+
+/*
+SyncAdapter.java
+Copyright (C) 2015 Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+import android.accounts.Account;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+
+public class SyncAdapter extends AbstractThreadedSyncAdapter {
+
+ public SyncAdapter(Context context, boolean autoInitialize) {
+ super(context, autoInitialize);
+ }
+
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority,
+ ContentProviderClient provider, SyncResult syncResult) {
+ }
+}
+
diff --git a/src/org/linphone/sync/SyncService.java b/src/org/linphone/sync/SyncService.java
new file mode 100755
index 000000000..fc9ee6638
--- /dev/null
+++ b/src/org/linphone/sync/SyncService.java
@@ -0,0 +1,45 @@
+package org.linphone.sync;
+
+/*
+SyncService.java
+Copyright (C) 2015 Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class SyncService extends Service {
+ private static SyncAdapter sSyncAdapter = null;
+ private static final Object sSyncAdapterLock = new Object();
+
+ @Override
+ public void onCreate() {
+
+ synchronized (sSyncAdapterLock) {
+ if (sSyncAdapter == null) {
+ sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
+ }
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return sSyncAdapter.getSyncAdapterBinder();
+ }
+}
diff --git a/submodules/linphone b/submodules/linphone
index 54b161f8d..ef7677a88 160000
--- a/submodules/linphone
+++ b/submodules/linphone
@@ -1 +1 @@
-Subproject commit 54b161f8d0c5507c38fa76cf1e6f4bd2f38f66b7
+Subproject commit ef7677a88d7aaef4168f884eeaca85af2994ecd9