Huge improvement on contacts loading time
This commit is contained in:
parent
d2fad6fcf1
commit
06da98f191
4 changed files with 126 additions and 67 deletions
|
@ -183,7 +183,7 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
|
|||
LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACT_DETAIL);
|
||||
LinphoneActivity.instance().hideTabBar(false);
|
||||
}
|
||||
contact.minimalRefresh(true);
|
||||
contact.refresh();
|
||||
displayContact(inflater, view);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ public class ContactsManager extends ContentObserver {
|
|||
private Context context;
|
||||
private ContactsFetchTask contactsFetchTask;
|
||||
private HashMap<String, LinphoneContact> contactsCache;
|
||||
private HashMap<String, LinphoneContact> androidContactsCache;
|
||||
private LinphoneContact contactNotFound;
|
||||
private Bitmap defaultAvatar;
|
||||
|
||||
|
@ -91,6 +92,7 @@ public class ContactsManager extends ContentObserver {
|
|||
defaultAvatar = BitmapFactory.decodeResource(LinphoneService.instance().getResources(), R.drawable.avatar);
|
||||
contactNotFound = new LinphoneContact();
|
||||
contactsCache = new HashMap<String, LinphoneContact>();
|
||||
androidContactsCache = new HashMap<String, LinphoneContact>();
|
||||
contactsUpdatedListeners = new ArrayList<ContactsUpdatedListener>();
|
||||
contacts = new ArrayList<LinphoneContact>();
|
||||
sipContacts = new ArrayList<LinphoneContact>();
|
||||
|
@ -292,13 +294,17 @@ public class ContactsManager extends ContentObserver {
|
|||
sipContacts = c;
|
||||
}
|
||||
|
||||
public synchronized void refreshSipContacts() {
|
||||
public synchronized void refreshSipContact(LinphoneFriend lf) {
|
||||
for (LinphoneContact contact : contacts) {
|
||||
if (contact.isInLinphoneFriendList() && !sipContacts.contains(contact)) {
|
||||
sipContacts.add(contact);
|
||||
if (contact.getLinphoneFriend() == lf) {
|
||||
if (contact.isInLinphoneFriendList() && !sipContacts.contains(contact)) {
|
||||
sipContacts.add(contact);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Collections.sort(sipContacts);
|
||||
|
||||
for (ContactsUpdatedListener listener : contactsUpdatedListeners) {
|
||||
listener.onContactsUpdated();
|
||||
}
|
||||
|
@ -327,6 +333,7 @@ public class ContactsManager extends ContentObserver {
|
|||
List<LinphoneContact> contacts = new ArrayList<LinphoneContact>();
|
||||
List<LinphoneContact> sipContacts = new ArrayList<LinphoneContact>();
|
||||
Date contactsTime = new Date();
|
||||
androidContactsCache.clear();
|
||||
|
||||
//We need to check sometimes to know if Linphone was destroyed
|
||||
if (this.isCancelled()) {
|
||||
|
@ -340,12 +347,31 @@ public class ContactsManager extends ContentObserver {
|
|||
String id = c.getString(c.getColumnIndex(Data.CONTACT_ID));
|
||||
String displayName = c.getString(c.getColumnIndex(Data.DISPLAY_NAME_PRIMARY));
|
||||
LinphoneContact contact = new LinphoneContact();
|
||||
|
||||
contact.setFullName(displayName);
|
||||
contact.setAndroidId(id);
|
||||
/*contact.getAndroidIds();*/
|
||||
contacts.add(contact);
|
||||
androidContactsCache.put(id, contact);
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
|
||||
boolean isOrgVisible = LinphoneManager.getInstance().getContext().getResources().getBoolean(R.bool.display_contact_organization);
|
||||
if (isOrgVisible) {
|
||||
c = getOrganizationCursor(contentResolver);
|
||||
if (c != null) {
|
||||
while (c.moveToNext()) {
|
||||
String id = c.getString(c.getColumnIndex(ContactsContract.Data.CONTACT_ID));
|
||||
String org = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY));
|
||||
LinphoneContact contact = androidContactsCache.get(id);
|
||||
if (contact != null) {
|
||||
contact.setOrganization(org);
|
||||
}
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w("[Permission] Read contacts permission wasn't granted, only fetch LinphoneFriends");
|
||||
}
|
||||
|
@ -354,7 +380,7 @@ public class ContactsManager extends ContentObserver {
|
|||
TimeUnit.MILLISECONDS.toMinutes(timeElapsed),
|
||||
TimeUnit.MILLISECONDS.toSeconds(timeElapsed) -
|
||||
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed)));
|
||||
Log.i("[ContactsManager] got " + contacts.size() + " contacts names and pictures in " + time);
|
||||
Log.i("[ContactsManager] Step 1 for " + contacts.size() + " contacts executed in " + time);
|
||||
|
||||
//We need to check sometimes to know if Linphone was destroyed
|
||||
if (this.isCancelled()) {
|
||||
|
@ -382,6 +408,10 @@ public class ContactsManager extends ContentObserver {
|
|||
// Refkey not null but no contact access => can't link it to native contact so display it on is own
|
||||
LinphoneContact contact = new LinphoneContact();
|
||||
contact.setFriend(friend);
|
||||
contact.refresh();
|
||||
if (contact.hasAddress()) {
|
||||
sipContacts.add(contact);
|
||||
}
|
||||
contacts.add(contact);
|
||||
}
|
||||
} else {
|
||||
|
@ -392,66 +422,78 @@ public class ContactsManager extends ContentObserver {
|
|||
// No refkey so it's a standalone contact
|
||||
LinphoneContact contact = new LinphoneContact();
|
||||
contact.setFriend(friend);
|
||||
contact.refresh();
|
||||
if (contact.hasAddress()) {
|
||||
sipContacts.add(contact);
|
||||
}
|
||||
contacts.add(contact);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (LinphoneContact contact : contacts) {
|
||||
//We need to check sometimes to know if Linphone was destroyed
|
||||
if (this.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
// This will only get name & picture informations to be able to quickly display contacts list
|
||||
contact.minimalRefresh();
|
||||
i++;
|
||||
if (contact.hasAddress()) {
|
||||
sipContacts.add(contact);
|
||||
}
|
||||
|
||||
if (i == CONTACTS_STEP) {
|
||||
i = 0;
|
||||
publishProgress(new ContactsLists(contacts, sipContacts));
|
||||
}
|
||||
}
|
||||
Collections.sort(contacts);
|
||||
Collections.sort(sipContacts);
|
||||
publishProgress(new ContactsLists(contacts, sipContacts));
|
||||
|
||||
//We need to check sometimes to know if Linphone was destroyed
|
||||
if (this.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hasContactsAccess()) {
|
||||
Cursor c = getPhonesCursor(contentResolver);
|
||||
if (c != null) {
|
||||
while (c.moveToNext()) {
|
||||
String id = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
|
||||
String number = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
|
||||
LinphoneContact contact = androidContactsCache.get(id);
|
||||
if (contact != null) {
|
||||
contact.addNumberOrAddress(new LinphoneNumberOrAddress(number, false));
|
||||
}
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
c = getSipCursor(contentResolver);
|
||||
if (c != null) {
|
||||
while (c.moveToNext()) {
|
||||
String id = c.getString(c.getColumnIndex(ContactsContract.Data.CONTACT_ID));
|
||||
String sip = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS));
|
||||
LinphoneContact contact = androidContactsCache.get(id);
|
||||
if (contact != null) {
|
||||
contact.addNumberOrAddress(new LinphoneNumberOrAddress(sip, true));
|
||||
if (!sipContacts.contains(contact)) {
|
||||
sipContacts.add(contact);
|
||||
}
|
||||
}
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
Collections.sort(sipContacts);
|
||||
}
|
||||
publishProgress(new ContactsLists(contacts, sipContacts));
|
||||
|
||||
timeElapsed = (new Date()).getTime() - contactsTime.getTime();
|
||||
time = String.format("%02d:%02d",
|
||||
TimeUnit.MILLISECONDS.toMinutes(timeElapsed),
|
||||
TimeUnit.MILLISECONDS.toSeconds(timeElapsed) -
|
||||
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed)));
|
||||
Log.i("[ContactsManager] organization, SIP and phone numbers for " + contacts.size() + " contacts fetched in " + time);
|
||||
// Public the current list of contacts without all the informations populated
|
||||
publishProgress(new ContactsLists(contacts, sipContacts));
|
||||
|
||||
Log.i("[ContactsManager] Step 2 for " + contacts.size() + " contacts executed in " + time);
|
||||
|
||||
for (LinphoneContact contact : contacts) {
|
||||
//We need to check sometimes to know if Linphone was destroyed
|
||||
if (this.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
// This time fetch all informations including phone numbers and SIP addresses
|
||||
contact.refresh();
|
||||
|
||||
if (contact.isInLinphoneFriendList() && !sipContacts.contains(contact)) {
|
||||
sipContacts.add(contact);
|
||||
}
|
||||
// Create the LinphoneFriends matching the native contacts
|
||||
contact.createOrUpdateLinphoneFriendFromNativeContact();
|
||||
}
|
||||
timeElapsed = (new Date()).getTime() - contactsTime.getTime();
|
||||
time = String.format("%02d:%02d",
|
||||
TimeUnit.MILLISECONDS.toMinutes(timeElapsed),
|
||||
TimeUnit.MILLISECONDS.toSeconds(timeElapsed) -
|
||||
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed)));
|
||||
Log.i("[ContactsManager] linphone friends for " + contacts.size() + " contacts created in " + time);
|
||||
Log.i("[ContactsManager] Step 3 for " + contacts.size() + " contacts executed in " + time);
|
||||
|
||||
for (LinphoneFriendList lfl : lc.getFriendLists()) {
|
||||
Log.d("[ContactsManager] Updating friends subscribtions");
|
||||
lfl.updateSubscriptions();
|
||||
}
|
||||
|
||||
androidContactsCache.clear();
|
||||
return new ContactsLists(contacts, sipContacts);
|
||||
}
|
||||
|
||||
|
@ -467,6 +509,8 @@ public class ContactsManager extends ContentObserver {
|
|||
}
|
||||
|
||||
protected void onPostExecute(ContactsLists result) {
|
||||
Log.d("[ContactsManager] Updating contacts subscribtions");
|
||||
LinphoneManager.getLc().getFriendLists()[0].updateSubscriptions();
|
||||
for (ContactsUpdatedListener listener : contactsUpdatedListeners) {
|
||||
listener.onContactsUpdated();
|
||||
}
|
||||
|
@ -560,4 +604,25 @@ public class ContactsManager extends ContentObserver {
|
|||
cursor.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
private Cursor getPhonesCursor(ContentResolver cr) {
|
||||
Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
|
||||
new String[] { ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.CONTACT_ID },
|
||||
null, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " ASC");
|
||||
return cursor;
|
||||
}
|
||||
|
||||
private Cursor getSipCursor(ContentResolver cr) {
|
||||
String select = ContactsContract.Data.MIMETYPE + "=?";
|
||||
String[] projection = new String[] { ContactsContract.Data.CONTACT_ID, ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS };
|
||||
Cursor c = cr.query(ContactsContract.Data.CONTENT_URI, projection, select, new String[]{ ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE }, null);
|
||||
return c;
|
||||
}
|
||||
|
||||
private Cursor getOrganizationCursor(ContentResolver cr) {
|
||||
String select = ContactsContract.Data.MIMETYPE + "=?";
|
||||
String[] projection = new String[] { ContactsContract.Data.CONTACT_ID, ContactsContract.CommonDataKinds.Organization.COMPANY };
|
||||
Cursor c = cr.query(ContactsContract.Data.CONTENT_URI, projection, select, new String[]{ ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE }, null);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -399,6 +399,10 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
public String getAndroidId() {
|
||||
return androidId;
|
||||
}
|
||||
|
||||
public LinphoneFriend getLinphoneFriend() {
|
||||
return friend;
|
||||
}
|
||||
|
||||
private void createOrUpdateFriend() {
|
||||
boolean created = false;
|
||||
|
@ -494,24 +498,14 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
LinphoneManager.getLcIfManagerNotDestroyedOrNull().removeFriend(friend);
|
||||
}
|
||||
}
|
||||
|
||||
public void minimalRefresh() {
|
||||
minimalRefresh(false);
|
||||
}
|
||||
|
||||
public void minimalRefresh(boolean getAllNames) {
|
||||
addresses = new ArrayList<LinphoneNumberOrAddress>();
|
||||
hasSipAddress = false;
|
||||
|
||||
public void refresh() {
|
||||
if (isAndroidContact()) {
|
||||
if (getAllNames) {
|
||||
getContactNames();
|
||||
}
|
||||
boolean isOrgVisible = LinphoneManager.getInstance().getContext().getResources().getBoolean(R.bool.display_contact_organization);
|
||||
if (isOrgVisible) {
|
||||
getNativeContactOrganization();
|
||||
}
|
||||
|
||||
getContactNames();
|
||||
getNativeContactOrganization();
|
||||
getAndroidIds();
|
||||
hasSipAddress = false;
|
||||
addresses = new ArrayList<LinphoneNumberOrAddress>();
|
||||
for (LinphoneNumberOrAddress noa : getAddressesAndNumbersForAndroidContact()) {
|
||||
addNumberOrAddress(noa);
|
||||
}
|
||||
|
@ -543,14 +537,8 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
}
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
public void createOrUpdateLinphoneFriendFromNativeContact() {
|
||||
if (isAndroidContact()) {
|
||||
androidRawId = findRawContactID();
|
||||
|
||||
if (LinphoneManager.getInstance().getContext().getResources().getBoolean(R.bool.use_linphone_tag)) {
|
||||
androidTagId = findLinphoneRawContactId();
|
||||
}
|
||||
|
||||
createOrUpdateFriend();
|
||||
}
|
||||
}
|
||||
|
@ -584,6 +572,13 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
public void setFriend(LinphoneFriend f) {
|
||||
friend = f;
|
||||
}
|
||||
|
||||
public void getAndroidIds() {
|
||||
androidRawId = findRawContactID();
|
||||
if (LinphoneManager.getInstance().getContext().getResources().getBoolean(R.bool.use_linphone_tag)) {
|
||||
androidTagId = findLinphoneRawContactId();
|
||||
}
|
||||
}
|
||||
|
||||
public static LinphoneContact createContact() {
|
||||
if (ContactsManager.getInstance().hasContactsAccess()) {
|
||||
|
@ -604,7 +599,7 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
|
||||
private void getContactNames() {
|
||||
ContentResolver resolver = ContactsManager.getInstance().getContentResolver();
|
||||
String[] proj = new String[]{ ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, ContactsContract.Contacts.DISPLAY_NAME };
|
||||
String[] proj = new String[]{ ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME };
|
||||
String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?";
|
||||
String[] args = new String[]{ getAndroidId(), ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE };
|
||||
Cursor c = resolver.query(ContactsContract.Data.CONTENT_URI, proj, select, args, null);
|
||||
|
@ -612,7 +607,6 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
|
|||
if (c.moveToFirst()) {
|
||||
firstName = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
|
||||
lastName = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
|
||||
fullName = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
|
|
|
@ -1001,7 +1001,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
|
|||
public void show(LinphoneCore lc) {}
|
||||
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url) {}
|
||||
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {
|
||||
ContactsManager.getInstance().refreshSipContacts();
|
||||
ContactsManager.getInstance().refreshSipContact(lf);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue