Now that contacts loading are lightning fast, stop fetching them from async task + fixed contacts refreshing when rotating device

This commit is contained in:
Sylvain Berfini 2017-02-16 12:13:13 +01:00
parent 90a013dece
commit 234983f0af
3 changed files with 153 additions and 213 deletions

View file

@ -48,7 +48,6 @@ import android.database.MatrixCursor;
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.AsyncTask;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.provider.ContactsContract; import android.provider.ContactsContract;
@ -60,13 +59,12 @@ interface ContactsUpdatedListener {
} }
public class ContactsManager extends ContentObserver { public class ContactsManager extends ContentObserver {
public static int CONTACTS_STEP = 15;
private static ContactsManager instance; private static ContactsManager instance;
private List<LinphoneContact> contacts, sipContacts; private List<LinphoneContact> contacts, sipContacts;
private boolean preferLinphoneContacts = false, isContactPresenceDisabled = true, hasContactAccess = false; private boolean preferLinphoneContacts = false, isContactPresenceDisabled = true, hasContactAccess = false;
private ContentResolver contentResolver; private ContentResolver contentResolver;
private Context context; private Context context;
private ContactsFetchTask contactsFetchTask;
private HashMap<String, LinphoneContact> contactsCache; private HashMap<String, LinphoneContact> contactsCache;
private HashMap<String, LinphoneContact> androidContactsCache; private HashMap<String, LinphoneContact> androidContactsCache;
private LinphoneContact contactNotFound; private LinphoneContact contactNotFound;
@ -99,13 +97,13 @@ public class ContactsManager extends ContentObserver {
} }
public void destroy() { public void destroy() {
if (contactsFetchTask != null && !contactsFetchTask.isCancelled()) {
contactsFetchTask.cancel(true);
}
defaultAvatar.recycle(); defaultAvatar.recycle();
instance = null; instance = null;
} }
public boolean contactsFetchedOnce() {
return contacts.size() > 0;
}
public Bitmap getDefaultAvatarBitmap() { public Bitmap getDefaultAvatarBitmap() {
return defaultAvatar; return defaultAvatar;
@ -118,31 +116,31 @@ public class ContactsManager extends ContentObserver {
@Override @Override
public void onChange(boolean selfChange, Uri uri) { public void onChange(boolean selfChange, Uri uri) {
fetchContactsAsync(); fetchContactsSync();
} }
public ContentResolver getContentResolver() { public ContentResolver getContentResolver() {
return contentResolver; return contentResolver;
} }
public static final synchronized ContactsManager getInstance() { public static final ContactsManager getInstance() {
if (instance == null) instance = new ContactsManager(handler); if (instance == null) instance = new ContactsManager(handler);
return instance; return instance;
} }
public synchronized boolean hasContacts() { public boolean hasContacts() {
return contacts.size() > 0; return contacts.size() > 0;
} }
public synchronized List<LinphoneContact> getContacts() { public List<LinphoneContact> getContacts() {
return contacts; return contacts;
} }
public synchronized List<LinphoneContact> getSIPContacts() { public List<LinphoneContact> getSIPContacts() {
return sipContacts; return sipContacts;
} }
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<LinphoneContact>();
List<LinphoneContact> searchContactsContain = new ArrayList<LinphoneContact>(); List<LinphoneContact> searchContactsContain = new ArrayList<LinphoneContact>();
@ -159,7 +157,7 @@ public class ContactsManager extends ContentObserver {
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<LinphoneContact>();
List<LinphoneContact> searchContactsContain = new ArrayList<LinphoneContact>(); List<LinphoneContact> searchContactsContain = new ArrayList<LinphoneContact>();
@ -223,7 +221,7 @@ public class ContactsManager extends ContentObserver {
initializeContactManager(context, contentResolver); initializeContactManager(context, contentResolver);
} }
public synchronized LinphoneContact findContactFromAddress(LinphoneAddress address) { public LinphoneContact findContactFromAddress(LinphoneAddress address) {
String sipUri = address.asStringUriOnly(); String sipUri = address.asStringUriOnly();
String username = address.getUserName(); String username = address.getUserName();
@ -257,7 +255,7 @@ public class ContactsManager extends ContentObserver {
return null; return null;
} }
public synchronized LinphoneContact findContactFromPhoneNumber(String phoneNumber) { public LinphoneContact findContactFromPhoneNumber(String phoneNumber) {
LinphoneContact cache = contactsCache.get(phoneNumber); LinphoneContact cache = contactsCache.get(phoneNumber);
if (cache != null) { if (cache != null) {
if (cache == contactNotFound) return null; if (cache == contactNotFound) return null;
@ -286,15 +284,15 @@ public class ContactsManager extends ContentObserver {
return null; return null;
} }
public synchronized void setContacts(List<LinphoneContact> c) { public void setContacts(List<LinphoneContact> c) {
contacts = c; contacts = c;
} }
public synchronized void setSipContacts(List<LinphoneContact> c) { public void setSipContacts(List<LinphoneContact> c) {
sipContacts = c; sipContacts = c;
} }
public synchronized void refreshSipContact(LinphoneFriend lf) { public void refreshSipContact(LinphoneFriend lf) {
LinphoneContact contact = (LinphoneContact)((LinphoneFriendImpl)lf).getUserData(); LinphoneContact contact = (LinphoneContact)((LinphoneFriendImpl)lf).getUserData();
if (!sipContacts.contains(contact)) { if (!sipContacts.contains(contact)) {
sipContacts.add(contact); sipContacts.add(contact);
@ -306,36 +304,12 @@ public class ContactsManager extends ContentObserver {
} }
} }
public synchronized void fetchContactsAsync() { public void fetchContactsSync() {
if (contactsFetchTask != null && !contactsFetchTask.isCancelled()) {
contactsFetchTask.cancel(true);
}
contactsFetchTask = new ContactsFetchTask();
contactsFetchTask.execute();
}
private class ContactsLists {
public List<LinphoneContact> contacts;
public List<LinphoneContact> sipContacts;
public ContactsLists(List<LinphoneContact> c, List<LinphoneContact> s) {
contacts = c;
sipContacts = s;
}
}
private class ContactsFetchTask extends AsyncTask<Void, ContactsLists, ContactsLists> {
protected ContactsLists doInBackground(Void... params) {
List<LinphoneContact> contacts = new ArrayList<LinphoneContact>(); List<LinphoneContact> contacts = new ArrayList<LinphoneContact>();
List<LinphoneContact> sipContacts = new ArrayList<LinphoneContact>(); List<LinphoneContact> sipContacts = new ArrayList<LinphoneContact>();
Date contactsTime = new Date(); Date contactsTime = new Date();
androidContactsCache.clear(); androidContactsCache.clear();
//We need to check sometimes to know if Linphone was destroyed
if (this.isCancelled()) {
return null;
}
if (hasContactsAccess()) { if (hasContactsAccess()) {
Cursor c = getContactsCursor(contentResolver); Cursor c = getContactsCursor(contentResolver);
if (c != null) { if (c != null) {
@ -378,10 +352,6 @@ public class ContactsManager extends ContentObserver {
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed))); TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed)));
Log.i("[ContactsManager] Step 1 for " + contacts.size() + " contacts executed 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()) {
return null;
}
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) { if (lc != null) {
for (LinphoneFriend friend : lc.getFriendList()) { for (LinphoneFriend friend : lc.getFriendList()) {
@ -426,14 +396,6 @@ public class ContactsManager extends ContentObserver {
} }
} }
} }
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()) { if (hasContactsAccess()) {
Cursor c = getPhonesCursor(contentResolver); Cursor c = getPhonesCursor(contentResolver);
@ -463,9 +425,7 @@ public class ContactsManager extends ContentObserver {
} }
c.close(); c.close();
} }
Collections.sort(sipContacts);
} }
publishProgress(new ContactsLists(contacts, sipContacts));
timeElapsed = (new Date()).getTime() - contactsTime.getTime(); timeElapsed = (new Date()).getTime() - contactsTime.getTime();
time = String.format("%02d:%02d", time = String.format("%02d:%02d",
@ -475,10 +435,6 @@ public class ContactsManager extends ContentObserver {
Log.i("[ContactsManager] Step 2 for " + contacts.size() + " contacts executed in " + time); Log.i("[ContactsManager] Step 2 for " + contacts.size() + " contacts executed in " + time);
for (LinphoneContact contact : contacts) { for (LinphoneContact contact : contacts) {
//We need to check sometimes to know if Linphone was destroyed
if (this.isCancelled()) {
return null;
}
// Create the LinphoneFriends matching the native contacts // Create the LinphoneFriends matching the native contacts
contact.createOrUpdateLinphoneFriendFromNativeContact(); contact.createOrUpdateLinphoneFriendFromNativeContact();
} }
@ -490,28 +446,17 @@ public class ContactsManager extends ContentObserver {
Log.i("[ContactsManager] Step 3 for " + contacts.size() + " contacts executed in " + time); Log.i("[ContactsManager] Step 3 for " + contacts.size() + " contacts executed in " + time);
androidContactsCache.clear(); androidContactsCache.clear();
return new ContactsLists(contacts, sipContacts); Collections.sort(contacts);
} Collections.sort(sipContacts);
setContacts(contacts);
protected void onProgressUpdate(ContactsLists... result) { setSipContacts(sipContacts);
synchronized (ContactsManager.this) {
setContacts(result[0].contacts);
setSipContacts(result[0].sipContacts);
contactsCache.clear(); contactsCache.clear();
for (ContactsUpdatedListener listener : contactsUpdatedListeners) {
listener.onContactsUpdated();
}
}
}
protected void onPostExecute(ContactsLists result) {
Log.d("[ContactsManager] Updating contacts subscribtions");
LinphoneManager.getLc().getFriendLists()[0].updateSubscriptions(); LinphoneManager.getLc().getFriendLists()[0].updateSubscriptions();
for (ContactsUpdatedListener listener : contactsUpdatedListeners) { for (ContactsUpdatedListener listener : contactsUpdatedListeners) {
listener.onContactsUpdated(); listener.onContactsUpdated();
} }
} }
}
public static String getAddressOrNumberForAndroidContact(ContentResolver resolver, Uri contactUri) { public static String getAddressOrNumberForAndroidContact(ContentResolver resolver, Uri contactUri) {
// Phone Numbers // Phone Numbers

View file

@ -133,7 +133,6 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
private RelativeLayout sideMenuContent, quitLayout, defaultAccount; private RelativeLayout sideMenuContent, quitLayout, defaultAccount;
private ListView accountsList, sideMenuItemList; private ListView accountsList, sideMenuItemList;
private ImageView menu; private ImageView menu;
private boolean fetchedContactsOnce = false;
private boolean doNotGoToCallActivity = false; private boolean doNotGoToCallActivity = false;
private List<String> sideMenuItems; private List<String> sideMenuItems;
private boolean callTransfer = false; private boolean callTransfer = false;
@ -1264,10 +1263,9 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
} }
if (readContactsI >= 0 && grantResults[readContactsI] == PackageManager.PERMISSION_GRANTED) { if (readContactsI >= 0 && grantResults[readContactsI] == PackageManager.PERMISSION_GRANTED) {
ContactsManager.getInstance().enableContactsAccess(); ContactsManager.getInstance().enableContactsAccess();
if (!fetchedContactsOnce) { if (!ContactsManager.getInstance().contactsFetchedOnce()) {
ContactsManager.getInstance().enableContactsAccess(); ContactsManager.getInstance().enableContactsAccess();
ContactsManager.getInstance().fetchContactsAsync(); ContactsManager.getInstance().fetchContactsSync();
fetchedContactsOnce = true;
} }
} }
} }
@ -1304,10 +1302,9 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
permissionsList.add(Manifest.permission.READ_CONTACTS); permissionsList.add(Manifest.permission.READ_CONTACTS);
} }
} else { } else {
if (!fetchedContactsOnce) { if (!ContactsManager.getInstance().contactsFetchedOnce()) {
ContactsManager.getInstance().enableContactsAccess(); ContactsManager.getInstance().enableContactsAccess();
ContactsManager.getInstance().fetchContactsAsync(); ContactsManager.getInstance().fetchContactsSync();
fetchedContactsOnce = true;
} }
} }
@ -1321,14 +1318,12 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
outState.putSerializable("currentFragment", currentFragment); outState.putSerializable("currentFragment", currentFragment);
outState.putBoolean("fetchedContactsOnce", fetchedContactsOnce);
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
@Override @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) { protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState); super.onRestoreInstanceState(savedInstanceState);
fetchedContactsOnce = savedInstanceState.getBoolean("fetchedContactsOnce");
} }
@Override @Override

View file

@ -463,7 +463,7 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
if (!ContactsManager.getInstance().hasContactsAccess()) { if (!ContactsManager.getInstance().hasContactsAccess()) {
// This refresh is only needed if app has no contacts permission to refresh the list of LinphoneFriends. // This refresh is only needed if app has no contacts permission to refresh the list of LinphoneFriends.
// Otherwise contacts will be refreshed due to changes in native contact and the handler in ContactsManager // Otherwise contacts will be refreshed due to changes in native contact and the handler in ContactsManager
ContactsManager.getInstance().fetchContactsAsync(); ContactsManager.getInstance().fetchContactsSync();
} }
} }