Added a custom setting to allow fetching all device contacts + added debu logs

This commit is contained in:
Sylvain Berfini 2019-07-01 15:05:18 +02:00
parent 6ba56bb8f2
commit 35a2010488
16 changed files with 133 additions and 75 deletions

View file

@ -34,8 +34,6 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import org.linphone.LinphoneService; import org.linphone.LinphoneService;
import org.linphone.R; import org.linphone.R;
import org.linphone.core.PresenceBasicStatus;
import org.linphone.core.PresenceModel;
import org.linphone.core.tools.Log; import org.linphone.core.tools.Log;
class AndroidContact implements Serializable { class AndroidContact implements Serializable {
@ -210,33 +208,16 @@ class AndroidContact implements Serializable {
} }
} }
public void updateNativeContactWithPresenceInfo(LinphoneContact contact) { void updateNativeContactWithPresenceInfo(String value) {
// creation of the raw contact with the presence information (tablet) if (!isLinphoneAddressMimeEntryAlreadyExisting(value)) {
createRawLinphoneContactFromExistingAndroidContactIfNeeded(); Log.d("[Contact] Adding presence information " + value);
for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) {
String value = noa.getValue();
if (value == null || value.isEmpty()) {
return;
}
// Test presence of the value
PresenceModel pm = contact.getFriend().getPresenceModelForUriOrTel(value);
// If presence is not null
if (pm != null && pm.getBasicStatus().equals(PresenceBasicStatus.Open)) {
Boolean action = hasLinphoneAddressMimeType();
// do the action on the contact only once if it has not been done
if (action) {
if (!noa.isSIPAddress()) {
addChangesToCommit( addChangesToCommit(
ContentProviderOperation.newInsert(Data.CONTENT_URI) ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, mAndroidRawId)
.withValue( .withValue(
ContactsContract.Data.RAW_CONTACT_ID, mAndroidRawId) ContactsContract.Data.MIMETYPE,
.withValue(
Data.MIMETYPE,
ContactsManager.getInstance() ContactsManager.getInstance()
.getString( .getString(R.string.linphone_address_mime_type))
R.string
.linphone_address_mime_type))
.withValue("data1", value) // phone number .withValue("data1", value) // phone number
.withValue( .withValue(
"data2", "data2",
@ -244,20 +225,19 @@ class AndroidContact implements Serializable {
.getString(R.string.app_name)) // Summary .getString(R.string.app_name)) // Summary
.withValue("data3", value) // Detail .withValue("data3", value) // Detail
.build()); .build());
saveChangesCommited();
}
}
}
} }
} }
private Boolean hasLinphoneAddressMimeType() { private boolean isLinphoneAddressMimeEntryAlreadyExisting(String value) {
Boolean action = true; boolean result = false;
ContentResolver resolver = LinphoneService.instance().getContentResolver(); ContentResolver resolver = LinphoneService.instance().getContentResolver();
String[] projection = {"data1", "data3"}; String[] projection = {"data1", "data3"};
String selection = String selection =
ContactsContract.Data.RAW_CONTACT_ID + "= ? AND " + Data.MIMETYPE + "= ?"; ContactsContract.Data.RAW_CONTACT_ID
+ " = ? AND "
+ Data.MIMETYPE
+ " = ? AND data1 = ?";
Cursor c = Cursor c =
resolver.query( resolver.query(
@ -267,16 +247,17 @@ class AndroidContact implements Serializable {
new String[] { new String[] {
mAndroidRawId, mAndroidRawId,
ContactsManager.getInstance() ContactsManager.getInstance()
.getString(R.string.linphone_address_mime_type) .getString(R.string.linphone_address_mime_type),
value
}, },
null); null);
if (c != null) { if (c != null) {
if (c.moveToFirst()) { if (c.moveToFirst()) {
action = false; result = true;
} }
c.close(); c.close();
} }
return action; return result;
} }
void addNumberOrAddress(String value, String oldValueToReplace, boolean isSIP) { void addNumberOrAddress(String value, String oldValueToReplace, boolean isSIP) {

View file

@ -1,13 +1,32 @@
package org.linphone.contacts; package org.linphone.contacts;
/*
AsyncContactPresence.java
Copyright (C) 2019 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.os.AsyncTask; import android.os.AsyncTask;
public class AsyncContactPresence extends AsyncTask<Void, AndroidContact, Void> { public class AsyncContactPresence extends AsyncTask<Void, AndroidContact, Void> {
private LinphoneContact linphoneContact; private LinphoneContact mLinphoneContact;
public AsyncContactPresence(LinphoneContact linphoneContact) { public AsyncContactPresence(LinphoneContact linphoneContact) {
this.linphoneContact = linphoneContact; mLinphoneContact = linphoneContact;
} }
@Override @Override
@ -17,7 +36,7 @@ public class AsyncContactPresence extends AsyncTask<Void, AndroidContact, Void>
@Override @Override
protected Void doInBackground(Void... voids) { protected Void doInBackground(Void... voids) {
linphoneContact.updateNativeContactWithPresenceInfo(linphoneContact); mLinphoneContact.updateNativeContactWithPresenceInfo();
return null; return null;
} }
} }

View file

@ -78,12 +78,19 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
@Override @Override
protected AsyncContactsData doInBackground(Void... params) { protected AsyncContactsData doInBackground(Void... params) {
Log.i("[Contacts Manager] Background synchronization started"); Log.i("[Contacts Manager] Background synchronization started");
String selection = null;
if (mContext.getResources().getBoolean(R.bool.fetch_contacts_from_default_directory)) {
Log.i("[Contacts Manager] Only fetching contacts in default directory");
selection = ContactsContract.Data.IN_DEFAULT_DIRECTORY + " == 1";
}
Cursor c = Cursor c =
mContext.getContentResolver() mContext.getContentResolver()
.query( .query(
ContactsContract.Data.CONTENT_URI, ContactsContract.Data.CONTENT_URI,
PROJECTION, PROJECTION,
ContactsContract.Data.IN_DEFAULT_DIRECTORY + " == 1", selection,
null, null,
null); null);
@ -141,6 +148,11 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
LinphoneContact contact = androidContactsCache.get(id); LinphoneContact contact = androidContactsCache.get(id);
if (contact == null) { if (contact == null) {
Log.d(
"[Contacts Manager] Creating LinphoneContact with native ID "
+ id
+ ", favorite flag is "
+ starred);
nativeIds.add(id); nativeIds.add(id);
contact = new LinphoneContact(); contact = new LinphoneContact();
contact.setAndroidId(id); contact.setAndroidId(id);

View file

@ -358,11 +358,18 @@ public class ContactsManager extends ContentObserver implements FriendListListen
public synchronized LinphoneContact findContactFromAddress(Address address) { public synchronized LinphoneContact findContactFromAddress(Address address) {
if (address == null) return null; if (address == null) return null;
Core core = LinphoneManager.getCore(); Core core = LinphoneManager.getCore();
Friend lf = core.findFriend(address); Friend lf = core.findFriend(address);
if (lf != null) { if (lf != null) {
return (LinphoneContact) lf.getUserData(); return (LinphoneContact) lf.getUserData();
} }
return findContactFromPhoneNumber(address.getUsername());
String username = address.getUsername();
if (android.util.Patterns.PHONE.matcher(username).matches()) {
return findContactFromPhoneNumber(username);
}
return null;
} }
public synchronized LinphoneContact findContactFromPhoneNumber(String phoneNumber) { public synchronized LinphoneContact findContactFromPhoneNumber(String phoneNumber) {

View file

@ -37,6 +37,7 @@ import org.linphone.core.FriendList;
import org.linphone.core.PresenceBasicStatus; import org.linphone.core.PresenceBasicStatus;
import org.linphone.core.PresenceModel; import org.linphone.core.PresenceModel;
import org.linphone.core.SubscribePolicy; import org.linphone.core.SubscribePolicy;
import org.linphone.core.tools.Log;
public class LinphoneContact extends AndroidContact public class LinphoneContact extends AndroidContact
implements Serializable, Comparable<LinphoneContact> { implements Serializable, Comparable<LinphoneContact> {
@ -208,18 +209,18 @@ public class LinphoneContact extends AndroidContact
boolean found = false; boolean found = false;
// Check for duplicated phone numbers but with different formats // Check for duplicated phone numbers but with different formats
for (LinphoneNumberOrAddress number : mAddresses) { for (LinphoneNumberOrAddress number : mAddresses) {
if (!number.isSIPAddress()) {
if ((!noa.isSIPAddress() if ((!noa.isSIPAddress()
&& !number.isSIPAddress()
&& noa.getNormalizedPhone().equals(number.getNormalizedPhone())) && noa.getNormalizedPhone().equals(number.getNormalizedPhone()))
|| (noa.isSIPAddress() || (noa.isSIPAddress()
&& !number.isSIPAddress()
&& noa.getValue().equals(number.getNormalizedPhone())) && noa.getValue().equals(number.getNormalizedPhone()))
|| (number.getValue().equals(noa.getNormalizedPhone()) || (noa.getNormalizedPhone().equals(number.getValue()))) {
|| !number.isSIPAddress())) { Log.d("[Linphone Contact] Duplicated entry detected: " + noa);
found = true; found = true;
break; break;
} }
} }
}
if (!found) { if (!found) {
if (noa.isSIPAddress()) { if (noa.isSIPAddress()) {
@ -538,24 +539,57 @@ public class LinphoneContact extends AndroidContact
String data4 = c.getString(c.getColumnIndex("data4")); String data4 = c.getString(c.getColumnIndex("data4"));
if (getFullName() == null) { if (getFullName() == null) {
Log.d("[Linphone Contact] Setting display name " + displayName);
setFullName(displayName); setFullName(displayName);
} }
if (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mime)) { if (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mime)) {
Log.d("[Linphone Contact] Found phone number " + data1 + " (" + data4 + ")");
addNumberOrAddress(new LinphoneNumberOrAddress(data1, data4)); addNumberOrAddress(new LinphoneNumberOrAddress(data1, data4));
} else if (ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE.equals(mime) } else if (ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE.equals(mime)
|| LinphoneService.instance() || LinphoneService.instance()
.getString(R.string.linphone_address_mime_type) .getString(R.string.linphone_address_mime_type)
.equals(mime)) { .equals(mime)) {
Log.d("[Linphone Contact] Found SIP address " + data1);
addNumberOrAddress(new LinphoneNumberOrAddress(data1, true)); addNumberOrAddress(new LinphoneNumberOrAddress(data1, true));
} else if (ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE.equals(mime)) { } else if (ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE.equals(mime)) {
Log.d("[Linphone Contact] Found organization " + data1);
setOrganization(data1, false); setOrganization(data1, false);
} else if (ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE.equals(mime)) { } else if (ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE.equals(mime)) {
Log.d("[Linphone Contact] Found first name " + data2 + " and last name " + data3);
setFirstNameAndLastName(data2, data3, false); setFirstNameAndLastName(data2, data3, false);
} else {
Log.w("[Linphone Contact] Unexpected MIME type " + mime);
} }
} }
public void updateNativeContactWithPresenceInfo() {
Log.d("[Contact] Trying to update native contact with presence information");
// Creation of the raw contact with the presence information (tablet)
createRawLinphoneContactFromExistingAndroidContactIfNeeded();
for (LinphoneNumberOrAddress noa : getNumbersOrAddresses()) {
if (noa.isSIPAddress()) {
// We are only interested in SIP addresses
continue;
}
String value = noa.getValue();
if (value == null || value.isEmpty()) {
return;
}
// Test presence of the value
PresenceModel pm = getFriend().getPresenceModelForUriOrTel(value);
// If presence is not null
if (pm != null && pm.getBasicStatus().equals(PresenceBasicStatus.Open)) {
Log.d("[Contact] Found presence information for phone number " + value);
// Do the action on the contact only once if it has not been done yet
updateNativeContactWithPresenceInfo(value);
}
}
saveChangesCommited();
}
public void save() { public void save() {
saveChangesCommited(); saveChangesCommited();
syncValuesFromAndroidContact(LinphoneService.instance()); syncValuesFromAndroidContact(LinphoneService.instance());

View file

@ -89,4 +89,8 @@ public class LinphoneNumberOrAddress implements Serializable, Comparable<Linphon
public String getNormalizedPhone() { public String getNormalizedPhone() {
return mNormalizedPhone != null ? mNormalizedPhone : mValue; return mNormalizedPhone != null ? mNormalizedPhone : mValue;
} }
public String toString() {
return (isSIPAddress() ? "sip:" : "tel:") + getNormalizedPhone();
}
} }

View file

@ -110,6 +110,7 @@
<bool name="hide_invite_contact">false</bool> <bool name="hide_invite_contact">false</bool>
<bool name="generate_text_avatar">true</bool> <bool name="generate_text_avatar">true</bool>
<bool name="only_show_address_username_if_matches_default_domain">true</bool> <bool name="only_show_address_username_if_matches_default_domain">true</bool>
<bool name="fetch_contacts_from_default_directory">true</bool> <!-- Recommended -->
<!-- Side Menu --> <!-- Side Menu -->
<bool name="hide_assistant_from_side_menu">false</bool> <bool name="hide_assistant_from_side_menu">false</bool>