Attempt to improve contacts fetching performances

This commit is contained in:
Sylvain Berfini 2018-11-09 16:53:35 +01:00
parent 6f9ccf2d94
commit b54692418f
3 changed files with 195 additions and 244 deletions

View file

@ -206,7 +206,7 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
ContactsManager.getInstance().initializeSyncAccount(this); ContactsManager.getInstance().initializeSyncAccount(this);
} }
} else { } else {
if (LinphoneService.isReady()) if (LinphoneService.isReady() && !ContactsManager.getInstance().contactsFetchedOnce())
ContactsManager.getInstance().initializeContactManager(this); ContactsManager.getInstance().initializeContactManager(this);
} }
@ -1286,7 +1286,9 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
ContactsManager.getInstance().initializeSyncAccount(this); ContactsManager.getInstance().initializeSyncAccount(this);
} else { } else {
ContactsManager.getInstance().initializeContactManager(this); if (!ContactsManager.getInstance().contactsFetchedOnce()) {
ContactsManager.getInstance().initializeContactManager(this);
}
} }
break; break;
case PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER: case PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER:

View file

@ -412,9 +412,6 @@ public class AssistantActivity extends Activity implements OnClickListener, Acti
if (LinphonePreferences.instance() != null) if (LinphonePreferences.instance() != null)
LinphonePreferences.instance().setPushNotificationEnabled(true); LinphonePreferences.instance().setPushNotificationEnabled(true);
if (ContactsManager.getInstance() != null)
ContactsManager.getInstance().fetchContactsAsync();
if (LinphonePreferences.instance() != null) if (LinphonePreferences.instance() != null)
mPrefs.enabledFriendlistSubscription(getResources().getBoolean(R.bool.use_friendlist_subscription)); mPrefs.enabledFriendlistSubscription(getResources().getBoolean(R.bool.use_friendlist_subscription));

View file

@ -23,30 +23,24 @@ import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.LoaderManager;
import android.content.ContentProviderOperation; import android.content.ContentProviderOperation;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.AsyncTask;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import android.provider.ContactsContract.Data; import android.provider.ContactsContract.Data;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.linphone.LinphoneManager; import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences; import org.linphone.LinphonePreferences;
import org.linphone.LinphoneService; import org.linphone.LinphoneService;
import org.linphone.LinphoneUtils; import org.linphone.LinphoneUtils;
import org.linphone.R; import org.linphone.R;
import org.linphone.activities.LinphoneActivity;
import org.linphone.core.Address; import org.linphone.core.Address;
import org.linphone.core.Core; import org.linphone.core.Core;
import org.linphone.core.Friend; import org.linphone.core.Friend;
@ -60,21 +54,21 @@ import org.linphone.mediastream.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit;
public class ContactsManager extends ContentObserver implements FriendListListener, LoaderManager.LoaderCallbacks<Cursor> { import static android.os.AsyncTask.THREAD_POOL_EXECUTOR;
public class ContactsManager extends ContentObserver implements FriendListListener {
private static ContactsManager instance; private static ContactsManager instance;
private List<LinphoneContact> mContacts, mSipContacts; private List<LinphoneContact> mContacts, mSipContacts;
private MagicSearch magicSearch; private MagicSearch magicSearch;
private Activity mActivity;
private HashMap<String, LinphoneContact> mAndroidContactsCache;
private Bitmap defaultAvatar; private Bitmap defaultAvatar;
private boolean mContactsFetchedOnce = false; private boolean mContactsFetchedOnce = false;
private Context mContext;
private AsyncContactsLoader mLoadContactTask;
private static ArrayList<ContactsUpdatedListener> contactsUpdatedListeners; private static ArrayList<ContactsUpdatedListener> contactsUpdatedListeners;
@ -89,7 +83,6 @@ public class ContactsManager extends ContentObserver implements FriendListListen
private ContactsManager() { private ContactsManager() {
super(LinphoneService.instance().mHandler); super(LinphoneService.instance().mHandler);
defaultAvatar = BitmapFactory.decodeResource(LinphoneService.instance().getResources(), R.drawable.avatar); defaultAvatar = BitmapFactory.decodeResource(LinphoneService.instance().getResources(), R.drawable.avatar);
mAndroidContactsCache = new HashMap<>();
contactsUpdatedListeners = new ArrayList<>(); contactsUpdatedListeners = new ArrayList<>();
mContacts = new ArrayList<>(); mContacts = new ArrayList<>();
mSipContacts = new ArrayList<>(); mSipContacts = new ArrayList<>();
@ -129,7 +122,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
@Override @Override
public void onChange(boolean selfChange, Uri uri) { public void onChange(boolean selfChange, Uri uri) {
fetchContactsSync(); fetchContactsAsync();
} }
public static final ContactsManager getInstance() { public static final ContactsManager getInstance() {
@ -141,19 +134,23 @@ public class ContactsManager extends ContentObserver implements FriendListListen
return mContacts.size() > 0; return mContacts.size() > 0;
} }
public synchronized List<LinphoneContact> getContacts() { public List<LinphoneContact> getContacts() {
return mContacts; synchronized (mContacts) {
return mContacts;
}
} }
public synchronized List<LinphoneContact> getSIPContacts() { public List<LinphoneContact> getSIPContacts() {
return mSipContacts; synchronized (mSipContacts) {
return mSipContacts;
}
} }
public synchronized List<LinphoneContact> getContacts(String search) { public List<LinphoneContact> getContacts(String search) {
search = search.toLowerCase(Locale.getDefault()); search = search.toLowerCase(Locale.getDefault());
List<LinphoneContact> searchContactsBegin = new ArrayList<LinphoneContact>(); List<LinphoneContact> searchContactsBegin = new ArrayList<>();
List<LinphoneContact> searchContactsContain = new ArrayList<LinphoneContact>(); List<LinphoneContact> searchContactsContain = new ArrayList<>();
for (LinphoneContact contact : mContacts) { for (LinphoneContact contact : getContacts()) {
if (contact.getFullName() != null) { if (contact.getFullName() != null) {
if (contact.getFullName().toLowerCase(Locale.getDefault()).startsWith(search)) { if (contact.getFullName().toLowerCase(Locale.getDefault()).startsWith(search)) {
searchContactsBegin.add(contact); searchContactsBegin.add(contact);
@ -166,11 +163,11 @@ public class ContactsManager extends ContentObserver implements FriendListListen
return searchContactsBegin; return searchContactsBegin;
} }
public synchronized List<LinphoneContact> getSIPContacts(String search) { public List<LinphoneContact> getSIPContacts(String search) {
search = search.toLowerCase(Locale.getDefault()); search = search.toLowerCase(Locale.getDefault());
List<LinphoneContact> searchContactsBegin = new ArrayList<LinphoneContact>(); List<LinphoneContact> searchContactsBegin = new ArrayList<>();
List<LinphoneContact> searchContactsContain = new ArrayList<LinphoneContact>(); List<LinphoneContact> searchContactsContain = new ArrayList<>();
for (LinphoneContact contact : mSipContacts) { for (LinphoneContact contact : getSIPContacts()) {
if (contact.getFullName() != null) { if (contact.getFullName() != null) {
if (contact.getFullName().toLowerCase(Locale.getDefault()).startsWith(search)) { if (contact.getFullName().toLowerCase(Locale.getDefault()).startsWith(search)) {
searchContactsBegin.add(contact); searchContactsBegin.add(contact);
@ -183,17 +180,24 @@ public class ContactsManager extends ContentObserver implements FriendListListen
return searchContactsBegin; return searchContactsBegin;
} }
private void addSipContact(LinphoneContact contact) {
synchronized (mSipContacts) {
mSipContacts.add(contact);
Collections.sort(mSipContacts);
}
}
public void enableContactsAccess() { public void enableContactsAccess() {
LinphonePreferences.instance().disableFriendsStorage(); LinphonePreferences.instance().disableFriendsStorage();
} }
public boolean hasContactsAccess() { public boolean hasContactsAccess() {
if (mActivity == null) { if (mContext == null) {
return false; return false;
} }
boolean contactsR = (PackageManager.PERMISSION_GRANTED == boolean contactsR = (PackageManager.PERMISSION_GRANTED ==
mActivity.getPackageManager().checkPermission(android.Manifest.permission.READ_CONTACTS, mActivity.getPackageName())); mContext.getPackageManager().checkPermission(android.Manifest.permission.READ_CONTACTS, mContext.getPackageName()));
return contactsR && !mActivity.getResources().getBoolean(R.bool.force_use_of_linphone_friends); return contactsR && !mContext.getResources().getBoolean(R.bool.force_use_of_linphone_friends);
} }
public boolean isLinphoneContactsPrefered() { public boolean isLinphoneContactsPrefered() {
@ -202,17 +206,11 @@ public class ContactsManager extends ContentObserver implements FriendListListen
return false; return false;
} }
public void initializeContactManager(Activity activity) { public void initializeContactManager(Context context) {
if (mActivity == null) { mContext = context;
mActivity = activity;
} else if (mActivity != activity) { if (mContext != null && getContacts().size() == 0 && hasContactsAccess()) {
mActivity = activity; fetchContactsAsync();
}
if (mActivity == null && LinphoneActivity.isInstanciated()) {
mActivity = LinphoneActivity.instance();
}
if (mActivity != null && mContacts.size() == 0 && hasContactsAccess()) {
mActivity.getLoaderManager().initLoader(CONTACTS_LOADER, null, this);
} }
} }
@ -223,7 +221,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
Account[] accounts = accountManager.getAccountsByType(activity.getPackageName()); Account[] accounts = accountManager.getAccountsByType(activity.getPackageName());
if (accounts != null && accounts.length == 0) { if (accounts != null && accounts.length == 0) {
Account newAccount = new Account(mActivity.getString(R.string.sync_account_name), activity.getPackageName()); Account newAccount = new Account(getString(R.string.sync_account_name), activity.getPackageName());
try { try {
accountManager.addAccountExplicitly(newAccount, null, null); accountManager.addAccountExplicitly(newAccount, null, null);
} catch (Exception e) { } catch (Exception e) {
@ -268,9 +266,8 @@ public class ContactsManager extends ContentObserver implements FriendListListen
public synchronized boolean refreshSipContact(Friend lf) { public synchronized boolean refreshSipContact(Friend lf) {
LinphoneContact contact = (LinphoneContact) lf.getUserData(); LinphoneContact contact = (LinphoneContact) lf.getUserData();
if (contact != null && !mSipContacts.contains(contact)) { if (contact != null && !getSIPContacts().contains(contact)) {
mSipContacts.add(contact); addSipContact(contact);
Collections.sort(mSipContacts);
return true; return true;
} }
return false; return false;
@ -320,15 +317,15 @@ public class ContactsManager extends ContentObserver implements FriendListListen
} }
try { try {
mActivity.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) { } catch (Exception e) {
Log.e(e); Log.e(e);
} }
} }
public String getString(int resourceID) { public String getString(int resourceID) {
if (mActivity == null) return null; if (mContext == null) return null;
return mActivity.getString(resourceID); return mContext.getString(resourceID);
} }
@Override @Override
@ -363,246 +360,201 @@ public class ContactsManager extends ContentObserver implements FriendListListen
} }
} }
public void fetchContactsSync() {
if (mActivity == null && LinphoneActivity.isInstanciated()) {
mActivity = LinphoneActivity.instance();
}
if (mActivity == null) {
Log.w("Can't fetch contacts right now, activity is null...");
return;
}
mActivity.getLoaderManager().initLoader(CONTACTS_LOADER, null, this);
}
public void fetchContactsAsync() { public void fetchContactsAsync() {
fetchContactsSync(); if (mLoadContactTask != null) {
mLoadContactTask.cancel(true);
}
mLoadContactTask = new AsyncContactsLoader();
mLoadContactTask.executeOnExecutor(THREAD_POOL_EXECUTOR);
} }
private static final int CONTACTS_LOADER = 1;
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
private static final String[] PROJECTION = private static final String[] PROJECTION =
{ {
Data.CONTACT_ID, Data.CONTACT_ID,
ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
Data.MIMETYPE, Data.MIMETYPE,
"data1", //Company, Phone or SIP Address "data1", //Company, Phone or SIP Address
"data2", //ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME "data2", //ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME
"data3", //ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME "data3", //ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME
"data4", //Normalized phone number "data4", //Normalized phone number
}; };
@NonNull class AsyncContactsData {
@Override List<LinphoneContact> contacts;
public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) { List<LinphoneContact> sipContacts;
if (id == CONTACTS_LOADER) {
if (!hasContactsAccess()) { public AsyncContactsData() {
Log.w("[ContactsManager] Read contacts permission was denied"); contacts = new ArrayList<>();
return null; sipContacts = new ArrayList<>();
}
return new CursorLoader(
mActivity,
ContactsContract.Data.CONTENT_URI,
PROJECTION,
Data.IN_VISIBLE_GROUP + " == 1",
null,
null
);
} }
return null;
} }
@Override class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsData> {
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor c) { private HashMap<String, LinphoneContact> mAndroidContactsCache;
mContactsFetchedOnce = true;
Date contactsTime = new Date(); @Override
List<LinphoneContact> contacts = new ArrayList<>(); protected void onPreExecute() {
List<LinphoneContact> sipContacts = new ArrayList<>(); mAndroidContactsCache = new HashMap<>();
mAndroidContactsCache.clear(); mContactsFetchedOnce = true;
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (LinphonePreferences.instance() != null && LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
if (lc != null) { String rls = getString(R.string.rls_uri);
for (FriendList list : lc.getFriendsLists()) { for (FriendList list : LinphoneManager.getLc().getFriendsLists()) {
for (Friend friend : list.getFriends()) { if (rls != null && (list.getRlsAddress() == null || !list.getRlsAddress().asStringUriOnly().equals(rls))) {
LinphoneContact contact = (LinphoneContact) friend.getUserData(); list.setRlsUri(rls);
if (contact != null) { }
contact.clearAddresses(); list.setListener(ContactsManager.this);
if (contact.getAndroidId() != null) { }
mAndroidContactsCache.put(contact.getAndroidId(), contact); }
} }
} else {
if (friend.getRefKey() != null) { @Override
// Friend has a refkey and but no LinphoneContact => represents a native contact stored in db from a previous version of Linphone, remove it protected AsyncContactsData doInBackground(Void... params) {
list.removeFriend(friend); Cursor c = mContext.getContentResolver().query(ContactsContract.Data.CONTENT_URI, PROJECTION, Data.IN_VISIBLE_GROUP + " == 1", null, null);
AsyncContactsData data = new AsyncContactsData();
Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
for (FriendList list : lc.getFriendsLists()) {
for (Friend friend : list.getFriends()) {
if (isCancelled()) return data;
LinphoneContact contact = (LinphoneContact) friend.getUserData();
if (contact != null) {
contact.clearAddresses();
if (contact.getAndroidId() != null) {
mAndroidContactsCache.put(contact.getAndroidId(), contact);
}
} else { } else {
// No refkey so it's a standalone contact if (friend.getRefKey() != null) {
contact = new LinphoneContact(); // Friend has a refkey and but no LinphoneContact => represents a native contact stored in db from a previous version of Linphone, remove it
contact.setFriend(friend); list.removeFriend(friend);
contact.refresh(); } else {
contacts.add(contact); // No refkey so it's a standalone contact
if (contact.hasAddress()) { contact = new LinphoneContact();
sipContacts.add(contact); contact.setFriend(friend);
contact.refresh();
data.contacts.add(contact);
} }
} }
} }
} }
} }
}
if (c != null) { if (c != null) {
List<String> nativeIds = new ArrayList<>(); List<String> nativeIds = new ArrayList<>();
while (c.moveToNext()) { while (c.moveToNext()) {
String id = c.getString(c.getColumnIndex(Data.CONTACT_ID)); if (isCancelled()) return data;
String displayName = c.getString(c.getColumnIndex(Data.DISPLAY_NAME_PRIMARY));
String mime = c.getString(c.getColumnIndex(Data.MIMETYPE));
String data1 = c.getString(c.getColumnIndex("data1"));
String data2 = c.getString(c.getColumnIndex("data2"));
String data3 = c.getString(c.getColumnIndex("data3"));
String data4 = c.getString(c.getColumnIndex("data4"));
nativeIds.add(id); String id = c.getString(c.getColumnIndex(Data.CONTACT_ID));
LinphoneContact contact = mAndroidContactsCache.get(id); String displayName = c.getString(c.getColumnIndex(Data.DISPLAY_NAME_PRIMARY));
if (contact == null) { String mime = c.getString(c.getColumnIndex(Data.MIMETYPE));
contact = new LinphoneContact(); String data1 = c.getString(c.getColumnIndex("data1"));
contact.setAndroidId(id); String data2 = c.getString(c.getColumnIndex("data2"));
contact.setFullName(displayName); String data3 = c.getString(c.getColumnIndex("data3"));
mAndroidContactsCache.put(id, contact); String data4 = c.getString(c.getColumnIndex("data4"));
}
if (contact.getFullName() == null && displayName != null) { LinphoneContact contact = mAndroidContactsCache.get(id);
contact.setFullName(displayName); if (contact == null) {
nativeIds.add(id);
contact = new LinphoneContact();
contact.setAndroidId(id);
contact.setFullName(displayName);
mAndroidContactsCache.put(id, contact);
}
if (contact.getFullName() == null && displayName != null) {
contact.setFullName(displayName);
}
if (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mime)) {
contact.addNumberOrAddress(new LinphoneNumberOrAddress(data1, data4));
} else if (ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE.equals(mime) || getInstance().getString(R.string.sync_mimetype).equals(mime)) {
contact.addNumberOrAddress(new LinphoneNumberOrAddress(data1, true));
} else if (ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE.equals(mime)) {
contact.setOrganization(data1, false);
} else if (ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE.equals(mime)) {
contact.setFirstNameAndLastName(data2, data3, false);
}
} }
if (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mime)) { for (FriendList list : lc.getFriendsLists()) {
contact.addNumberOrAddress(new LinphoneNumberOrAddress(data1, data4)); for (Friend friend : list.getFriends()) {
} else if (ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE.equals(mime) || getInstance().getString(R.string.sync_mimetype).equals(mime)) { if (isCancelled()) return data;
contact.addNumberOrAddress(new LinphoneNumberOrAddress(data1, true));
} else if (ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE.equals(mime)) {
contact.setOrganization(data1, false);
} else if (ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE.equals(mime)) {
contact.setFirstNameAndLastName(data2, data3, false);
}
}
for (FriendList list : lc.getFriendsLists()) { LinphoneContact contact = (LinphoneContact) friend.getUserData();
for (Friend friend : list.getFriends()) { if (contact != null && contact.isAndroidContact()) {
LinphoneContact contact = (LinphoneContact) friend.getUserData(); String id = contact.getAndroidId();
if (contact != null && contact.isAndroidContact()) { if (id != null && !nativeIds.contains(id)) {
String id = contact.getAndroidId(); // Has been removed since last fetch
if (id != null && !nativeIds.contains(id)) { mAndroidContactsCache.remove(id);
// Has been removed since last fetch }
mAndroidContactsCache.remove(id);
} }
} }
} }
nativeIds.clear();
} }
nativeIds.clear();
for (LinphoneContact contact : mAndroidContactsCache.values()) { for (LinphoneContact contact : mAndroidContactsCache.values()) {
// Only add contact to contacts list once we are finished with it, helps prevent duplicates if (isCancelled()) return data;
int indexOf = contacts.indexOf(contact);
if (indexOf < 0) { boolean hideContactsWithoutPresence = mContext.getResources().getBoolean(R.bool.hide_sip_contacts_without_presence);
contacts.add(contact); if (contact.hasAddress()) {
if (contact.hasAddress()) { if (contact.getFullName() == null) {
if (mActivity.getResources().getBoolean(R.bool.hide_sip_contacts_without_presence)) { for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) {
if (contact.getFriend() != null) { if (noa.isSIPAddress()) {
for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) { contact.setFullName(LinphoneUtils.getAddressDisplayName(noa.getValue()));
PresenceModel pm = contact.getFriend().getPresenceModelForUriOrTel(noa.getValue()); Log.w("Couldn't find a display name for contact " + contact.getFullName() + ", used SIP address display name / username instead...");
if (pm != null && pm.getBasicStatus().equals(PresenceBasicStatus.Open)) { break;
sipContacts.add(contact); }
break; }
} }
if (hideContactsWithoutPresence) {
if (contact.getFriend() != null) {
for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) {
PresenceModel pm = contact.getFriend().getPresenceModelForUriOrTel(noa.getValue());
if (pm != null && pm.getBasicStatus().equals(PresenceBasicStatus.Open)) {
data.sipContacts.add(contact);
break;
} }
} }
} else {
sipContacts.add(contact);
}
}
} else {
Log.w("Contact " + contact.getFullName() + " (" + contact.getAndroidId() +
") is an exact duplicate of " + contacts.get(indexOf).getAndroidId());
}
}
}
for (LinphoneContact contact : contacts) {
// Create the Friends matching the native contacts
if (contact.getFullName() == null) {
if (contact.hasAddress()) {
for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) {
if (noa.isSIPAddress()) {
contact.setFullName(LinphoneUtils.getAddressDisplayName(noa.getValue()));
Log.w("Couldn't find a display name for contact " + contact.getFullName() + ", used SIP address display name / username instead...");
break;
} }
} else {
data.sipContacts.add(contact);
} }
} }
if (contact.getFullName() == null) { contact.createOrUpdateFriendFromNativeContact();
Log.e("Couldn't find a display name for contact " + contact); data.contacts.add(contact);
continue;
}
} }
contact.createOrUpdateFriendFromNativeContact(); mAndroidContactsCache.clear();
}
mAndroidContactsCache.clear();
setContacts(contacts); Collections.sort(data.contacts);
setSipContacts(sipContacts); Collections.sort(data.sipContacts);
if (LinphonePreferences.instance() != null && LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) { return data;
String rls = mActivity.getString(R.string.rls_uri);
for (FriendList list : LinphoneManager.getLc().getFriendsLists()) {
if (rls != null && (list.getRlsAddress() == null || !list.getRlsAddress().asStringUriOnly().equals(rls))) {
list.setRlsUri(rls);
}
list.setListener(this);
list.updateSubscriptions();
}
} }
long timeElapsed = (new Date()).getTime() - contactsTime.getTime(); @Override
String time = String.format(Locale.getDefault(), "%02d:%02d:%03d", protected void onPostExecute(AsyncContactsData data) {
TimeUnit.MILLISECONDS.toMinutes(timeElapsed), for (ContactsUpdatedListener listener : contactsUpdatedListeners) {
TimeUnit.MILLISECONDS.toSeconds(timeElapsed) - listener.onContactsUpdated();
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed)), }
TimeUnit.MILLISECONDS.toMillis(timeElapsed) -
TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(timeElapsed)));
Log.i("[ContactsManager] For " + contacts.size() + " contacts: " + time + " elapsed since starting");
for (ContactsUpdatedListener listener : contactsUpdatedListeners) { setContacts(data.contacts);
listener.onContactsUpdated(); setSipContacts(data.sipContacts);
} }
} }
@Override public void setContacts(List<LinphoneContact> c) {
public void onLoaderReset(@NonNull Loader<Cursor> loader) { synchronized (mContacts) {
}
public synchronized void setContacts(List<LinphoneContact> c) {
if (mContacts.isEmpty() || mContacts.size() > c.size()) {
mContacts = c; mContacts = c;
} else {
for (LinphoneContact contact : c) {
if (!mContacts.contains(contact)) {
mContacts.add(contact);
}
}
} }
Collections.sort(mContacts);
} }
public synchronized void setSipContacts(List<LinphoneContact> c) { public synchronized void setSipContacts(List<LinphoneContact> c) {
if (mSipContacts.isEmpty() || mSipContacts.size() > c.size()) { synchronized (mSipContacts) {
mSipContacts = c; mSipContacts = c;
} else {
for (LinphoneContact contact : c) {
if (!mSipContacts.contains(contact)) {
mSipContacts.add(contact);
}
}
} }
Collections.sort(mSipContacts);
} }
} }