Moved AsyncContactsLoader to it's own file
This commit is contained in:
parent
4a529b9691
commit
385e72ea9b
9 changed files with 312 additions and 280 deletions
|
@ -1164,9 +1164,10 @@ public class LinphoneActivity extends LinphoneGenericActivity
|
||||||
changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
|
changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void editContact(LinphoneContact contact) {
|
public void editContact(LinphoneContact contact, String sipUri) {
|
||||||
Bundle extras = new Bundle();
|
Bundle extras = new Bundle();
|
||||||
extras.putSerializable("Contact", contact);
|
extras.putSerializable("Contact", contact);
|
||||||
|
extras.putString("NewSipAdress", sipUri);
|
||||||
changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
|
changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,7 +346,7 @@ public class ChatMessagesFragment extends Fragment
|
||||||
if (LinphoneActivity.isInstanciated()) {
|
if (LinphoneActivity.isInstanciated()) {
|
||||||
LinphoneActivity.instance().selectMenu(CHAT);
|
LinphoneActivity.instance().selectMenu(CHAT);
|
||||||
}
|
}
|
||||||
ContactsManager.addContactsListener(this);
|
ContactsManager.getInstance().addContactsListener(this);
|
||||||
|
|
||||||
addVirtualKeyboardVisiblityListener();
|
addVirtualKeyboardVisiblityListener();
|
||||||
// Force hide keyboard
|
// Force hide keyboard
|
||||||
|
@ -381,7 +381,7 @@ public class ChatMessagesFragment extends Fragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
ContactsManager.removeContactsListener(this);
|
ContactsManager.getInstance().removeContactsListener(this);
|
||||||
removeVirtualKeyboardVisiblityListener();
|
removeVirtualKeyboardVisiblityListener();
|
||||||
LinphoneManager.getInstance().setCurrentChatRoomAddress(null);
|
LinphoneManager.getInstance().setCurrentChatRoomAddress(null);
|
||||||
if (mChatRoom != null) mChatRoom.removeListener(this);
|
if (mChatRoom != null) mChatRoom.removeListener(this);
|
||||||
|
@ -560,12 +560,14 @@ public class ChatMessagesFragment extends Fragment
|
||||||
}
|
}
|
||||||
if (item.getItemId() == R.id.add_to_contacts) {
|
if (item.getItemId() == R.id.add_to_contacts) {
|
||||||
Address address = message.getFromAddress();
|
Address address = message.getFromAddress();
|
||||||
String uri = address.asStringUriOnly();
|
if (address == null) return true;
|
||||||
if (address != null && address.getDisplayName() != null)
|
String uri = address.getUsername() + "@" + address.getDomain(); // Get a clean address
|
||||||
|
if (address.getDisplayName() != null) {
|
||||||
LinphoneActivity.instance()
|
LinphoneActivity.instance()
|
||||||
.displayContactsForEdition(
|
.displayContactsForEdition(uri, address.getDisplayName());
|
||||||
address.asStringUriOnly(), address.getDisplayName());
|
} else {
|
||||||
else LinphoneActivity.instance().displayContactsForEdition(uri);
|
LinphoneActivity.instance().displayContactsForEdition(uri);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.onContextItemSelected(item);
|
return super.onContextItemSelected(item);
|
||||||
|
|
|
@ -262,7 +262,7 @@ public class ChatRoomCreationFragment extends Fragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
ContactsManager.addContactsListener(this);
|
ContactsManager.getInstance().addContactsListener(this);
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
if (LinphoneActivity.isInstanciated()) {
|
if (LinphoneActivity.isInstanciated()) {
|
||||||
|
@ -282,7 +282,7 @@ public class ChatRoomCreationFragment extends Fragment
|
||||||
if (mChatRoom != null) {
|
if (mChatRoom != null) {
|
||||||
mChatRoom.removeListener(mChatRoomCreationListener);
|
mChatRoom.removeListener(mChatRoomCreationListener);
|
||||||
}
|
}
|
||||||
ContactsManager.removeContactsListener(this);
|
ContactsManager.getInstance().removeContactsListener(this);
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,7 @@ public class ChatRoomsFragment extends Fragment
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
ContactsManager.addContactsListener(this);
|
ContactsManager.getInstance().addContactsListener(this);
|
||||||
|
|
||||||
if (LinphoneManager.getLc().getCallsNb() > 0) {
|
if (LinphoneManager.getLc().getCallsNb() > 0) {
|
||||||
mBackToCallButton.setVisibility(View.VISIBLE);
|
mBackToCallButton.setVisibility(View.VISIBLE);
|
||||||
|
@ -250,7 +250,7 @@ public class ChatRoomsFragment extends Fragment
|
||||||
if (lc != null) {
|
if (lc != null) {
|
||||||
lc.removeListener(mListener);
|
lc.removeListener(mListener);
|
||||||
}
|
}
|
||||||
ContactsManager.removeContactsListener(this);
|
ContactsManager.getInstance().removeContactsListener(this);
|
||||||
mChatRoomsAdapter.clear();
|
mChatRoomsAdapter.clear();
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
257
app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java
Normal file
257
app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
package org.linphone.contacts;
|
||||||
|
|
||||||
|
/*
|
||||||
|
AsyncContactsLoader.java
|
||||||
|
Copyright (C) 2018 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.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.provider.ContactsContract;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import org.linphone.LinphoneManager;
|
||||||
|
import org.linphone.LinphoneService;
|
||||||
|
import org.linphone.R;
|
||||||
|
import org.linphone.core.Core;
|
||||||
|
import org.linphone.core.Friend;
|
||||||
|
import org.linphone.core.FriendList;
|
||||||
|
import org.linphone.core.PresenceBasicStatus;
|
||||||
|
import org.linphone.core.PresenceModel;
|
||||||
|
import org.linphone.mediastream.Log;
|
||||||
|
import org.linphone.settings.LinphonePreferences;
|
||||||
|
import org.linphone.utils.LinphoneUtils;
|
||||||
|
|
||||||
|
class AsyncContactsData {
|
||||||
|
final List<LinphoneContact> contacts;
|
||||||
|
final List<LinphoneContact> sipContacts;
|
||||||
|
|
||||||
|
AsyncContactsData() {
|
||||||
|
contacts = new ArrayList<>();
|
||||||
|
sipContacts = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsData> {
|
||||||
|
@SuppressLint("InlinedApi")
|
||||||
|
private static final String[] PROJECTION = {
|
||||||
|
ContactsContract.Data.CONTACT_ID,
|
||||||
|
ContactsContract.Contacts.LOOKUP_KEY,
|
||||||
|
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
|
||||||
|
ContactsContract.Data.MIMETYPE,
|
||||||
|
"data1", // Company, Phone or SIP Address
|
||||||
|
"data2", // ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME
|
||||||
|
"data3", // ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME
|
||||||
|
"data4", // Normalized phone number
|
||||||
|
};
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private HashMap<String, LinphoneContact> mAndroidContactsCache;
|
||||||
|
|
||||||
|
public AsyncContactsLoader(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
mAndroidContactsCache = new HashMap<>();
|
||||||
|
|
||||||
|
if (mContext == null) {
|
||||||
|
mContext = LinphoneService.instance().getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LinphonePreferences.instance() != null
|
||||||
|
&& LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
|
||||||
|
String rls = mContext.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(ContactsManager.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AsyncContactsData doInBackground(Void... params) {
|
||||||
|
Cursor c =
|
||||||
|
mContext.getContentResolver()
|
||||||
|
.query(
|
||||||
|
ContactsContract.Data.CONTENT_URI,
|
||||||
|
PROJECTION,
|
||||||
|
ContactsContract.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 {
|
||||||
|
if (friend.getRefKey() != null) {
|
||||||
|
// Friend has a refkey and but no LinphoneContact => represents a
|
||||||
|
// native contact stored in db from a previous version of Linphone,
|
||||||
|
// remove it
|
||||||
|
list.removeFriend(friend);
|
||||||
|
} else {
|
||||||
|
// No refkey so it's a standalone contact
|
||||||
|
contact = new LinphoneContact();
|
||||||
|
contact.setFriend(friend);
|
||||||
|
contact.refresh();
|
||||||
|
data.contacts.add(contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c != null) {
|
||||||
|
List<String> nativeIds = new ArrayList<>();
|
||||||
|
while (c.moveToNext()) {
|
||||||
|
if (isCancelled()) return data;
|
||||||
|
|
||||||
|
String id = c.getString(c.getColumnIndex(ContactsContract.Data.CONTACT_ID));
|
||||||
|
String displayName =
|
||||||
|
c.getString(c.getColumnIndex(ContactsContract.Data.DISPLAY_NAME_PRIMARY));
|
||||||
|
String mime = c.getString(c.getColumnIndex(ContactsContract.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"));
|
||||||
|
String lookupKey =
|
||||||
|
c.getString(c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
|
||||||
|
|
||||||
|
LinphoneContact contact = mAndroidContactsCache.get(id);
|
||||||
|
if (contact == null) {
|
||||||
|
nativeIds.add(id);
|
||||||
|
contact = new LinphoneContact();
|
||||||
|
contact.setAndroidId(id);
|
||||||
|
contact.setAndroidLookupKey(lookupKey);
|
||||||
|
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)
|
||||||
|
|| mContext.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
for (FriendList list : lc.getFriendsLists()) {
|
||||||
|
for (Friend friend : list.getFriends()) {
|
||||||
|
if (isCancelled()) return data;
|
||||||
|
|
||||||
|
LinphoneContact contact = (LinphoneContact) friend.getUserData();
|
||||||
|
if (contact != null && contact.isAndroidContact()) {
|
||||||
|
String id = contact.getAndroidId();
|
||||||
|
if (id != null && !nativeIds.contains(id)) {
|
||||||
|
// Has been removed since last fetch
|
||||||
|
mAndroidContactsCache.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nativeIds.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (LinphoneContact contact : mAndroidContactsCache.values()) {
|
||||||
|
if (isCancelled()) return data;
|
||||||
|
|
||||||
|
boolean hideContactsWithoutPresence =
|
||||||
|
mContext.getResources().getBoolean(R.bool.hide_sip_contacts_without_presence);
|
||||||
|
if (contact.hasAddress()) {
|
||||||
|
if (contact.getFullName() == null) {
|
||||||
|
for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) {
|
||||||
|
if (noa.isSIPAddress()) {
|
||||||
|
contact.setFullName(
|
||||||
|
LinphoneUtils.getAddressDisplayName(noa.getValue()));
|
||||||
|
Log.w(
|
||||||
|
"[Contacts Manager] Couldn't find a display name for contact "
|
||||||
|
+ contact.getFullName()
|
||||||
|
+ ", used SIP address display name / username instead...");
|
||||||
|
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 {
|
||||||
|
data.sipContacts.add(contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.contacts.add(contact);
|
||||||
|
}
|
||||||
|
mAndroidContactsCache.clear();
|
||||||
|
|
||||||
|
Collections.sort(data.contacts);
|
||||||
|
Collections.sort(data.sipContacts);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(AsyncContactsData data) {
|
||||||
|
for (ContactsUpdatedListener listener :
|
||||||
|
ContactsManager.getInstance().getContactsListeners()) {
|
||||||
|
listener.onContactsUpdated();
|
||||||
|
}
|
||||||
|
for (LinphoneContact contact : data.contacts) {
|
||||||
|
contact.createOrUpdateFriendFromNativeContact();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactsManager.getInstance().setContacts(data.contacts);
|
||||||
|
ContactsManager.getInstance().setSipContacts(data.sipContacts);
|
||||||
|
}
|
||||||
|
}
|
|
@ -189,11 +189,9 @@ public class ContactEditorFragment extends Fragment {
|
||||||
new TextWatcher() {
|
new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
if (mLastName.getText().length() > 0 || mFirstName.getText().length() > 0) {
|
mOk.setEnabled(
|
||||||
mOk.setEnabled(true);
|
mLastName.getText().length() > 0
|
||||||
} else {
|
|| mFirstName.getText().length() > 0);
|
||||||
mOk.setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -209,11 +207,9 @@ public class ContactEditorFragment extends Fragment {
|
||||||
new TextWatcher() {
|
new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
if (mFirstName.getText().length() > 0 || mLastName.getText().length() > 0) {
|
mOk.setEnabled(
|
||||||
mOk.setEnabled(true);
|
mFirstName.getText().length() > 0
|
||||||
} else {
|
|| mLastName.getText().length() > 0);
|
||||||
mOk.setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -323,7 +323,7 @@ public class ContactsFragment extends Fragment
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
ContactsManager.addContactsListener(this);
|
ContactsManager.getInstance().addContactsListener(this);
|
||||||
|
|
||||||
if (mEditConsumed) {
|
if (mEditConsumed) {
|
||||||
mEditOnClick = false;
|
mEditOnClick = false;
|
||||||
|
@ -342,7 +342,7 @@ public class ContactsFragment extends Fragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
ContactsManager.removeContactsListener(this);
|
ContactsManager.getInstance().removeContactsListener(this);
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ import static android.os.AsyncTask.THREAD_POOL_EXECUTOR;
|
||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ContentProviderOperation;
|
import android.content.ContentProviderOperation;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
@ -35,12 +34,9 @@ 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.AsyncTask;
|
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.provider.ContactsContract.Data;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import org.linphone.LinphoneActivity;
|
import org.linphone.LinphoneActivity;
|
||||||
|
@ -53,42 +49,32 @@ import org.linphone.core.Friend;
|
||||||
import org.linphone.core.FriendList;
|
import org.linphone.core.FriendList;
|
||||||
import org.linphone.core.FriendListListener;
|
import org.linphone.core.FriendListListener;
|
||||||
import org.linphone.core.MagicSearch;
|
import org.linphone.core.MagicSearch;
|
||||||
import org.linphone.core.PresenceBasicStatus;
|
|
||||||
import org.linphone.core.PresenceModel;
|
|
||||||
import org.linphone.core.ProxyConfig;
|
import org.linphone.core.ProxyConfig;
|
||||||
import org.linphone.mediastream.Log;
|
import org.linphone.mediastream.Log;
|
||||||
import org.linphone.settings.LinphonePreferences;
|
import org.linphone.settings.LinphonePreferences;
|
||||||
import org.linphone.utils.LinphoneUtils;
|
|
||||||
|
|
||||||
public class ContactsManager extends ContentObserver implements FriendListListener {
|
public class ContactsManager extends ContentObserver implements FriendListListener {
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
private static final String[] PROJECTION = {
|
|
||||||
Data.CONTACT_ID,
|
|
||||||
ContactsContract.Contacts.LOOKUP_KEY,
|
|
||||||
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
|
|
||||||
Data.MIMETYPE,
|
|
||||||
"data1", // Company, Phone or SIP Address
|
|
||||||
"data2", // ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME
|
|
||||||
"data3", // ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME
|
|
||||||
"data4", // Normalized phone number
|
|
||||||
};
|
|
||||||
|
|
||||||
private static ContactsManager sInstance;
|
private static ContactsManager sInstance;
|
||||||
private static ArrayList<ContactsUpdatedListener> sContactsUpdatedListeners;
|
|
||||||
|
|
||||||
private List<LinphoneContact> mContacts, mSipContacts;
|
private List<LinphoneContact> mContacts, mSipContacts;
|
||||||
|
private ArrayList<ContactsUpdatedListener> mContactsUpdatedListeners;
|
||||||
private MagicSearch mMagicSearch;
|
private MagicSearch mMagicSearch;
|
||||||
private final Bitmap mDefaultAvatar;
|
private final Bitmap mDefaultAvatar;
|
||||||
private boolean mContactsFetchedOnce = false;
|
private boolean mContactsFetchedOnce = false;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private AsyncContactsLoader mLoadContactTask;
|
private AsyncContactsLoader mLoadContactTask;
|
||||||
|
|
||||||
|
public static ContactsManager getInstance() {
|
||||||
|
if (sInstance == null) sInstance = new ContactsManager();
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
private ContactsManager() {
|
private ContactsManager() {
|
||||||
super(LinphoneService.instance().handler);
|
super(LinphoneService.instance().handler);
|
||||||
mDefaultAvatar =
|
mDefaultAvatar =
|
||||||
BitmapFactory.decodeResource(
|
BitmapFactory.decodeResource(
|
||||||
LinphoneService.instance().getResources(), R.drawable.avatar);
|
LinphoneService.instance().getResources(), R.drawable.avatar);
|
||||||
sContactsUpdatedListeners = new ArrayList<>();
|
mContactsUpdatedListeners = new ArrayList<>();
|
||||||
mContacts = new ArrayList<>();
|
mContacts = new ArrayList<>();
|
||||||
mSipContacts = new ArrayList<>();
|
mSipContacts = new ArrayList<>();
|
||||||
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) {
|
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) {
|
||||||
|
@ -96,17 +82,16 @@ public class ContactsManager extends ContentObserver implements FriendListListen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addContactsListener(ContactsUpdatedListener listener) {
|
public void addContactsListener(ContactsUpdatedListener listener) {
|
||||||
sContactsUpdatedListeners.add(listener);
|
mContactsUpdatedListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeContactsListener(ContactsUpdatedListener listener) {
|
public void removeContactsListener(ContactsUpdatedListener listener) {
|
||||||
sContactsUpdatedListeners.remove(listener);
|
mContactsUpdatedListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ContactsManager getInstance() {
|
public ArrayList<ContactsUpdatedListener> getContactsListeners() {
|
||||||
if (sInstance == null) sInstance = new ContactsManager();
|
return mContactsUpdatedListeners;
|
||||||
return sInstance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getAddressOrNumberForAndroidContact(
|
public static String getAddressOrNumberForAndroidContact(
|
||||||
|
@ -177,22 +162,20 @@ public class ContactsManager extends ContentObserver implements FriendListListen
|
||||||
return mContacts.size() > 0;
|
return mContacts.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<LinphoneContact> getContacts() {
|
public synchronized List<LinphoneContact> getContacts() {
|
||||||
synchronized (mContacts) {
|
return mContacts;
|
||||||
return mContacts;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setContacts(List<LinphoneContact> c) {
|
synchronized void setContacts(List<LinphoneContact> c) {
|
||||||
synchronized (mContacts) {
|
mContacts = c;
|
||||||
mContacts = c;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<LinphoneContact> getSIPContacts() {
|
public synchronized List<LinphoneContact> getSIPContacts() {
|
||||||
synchronized (mSipContacts) {
|
return mSipContacts;
|
||||||
return mSipContacts;
|
}
|
||||||
}
|
|
||||||
|
synchronized void setSipContacts(List<LinphoneContact> c) {
|
||||||
|
mSipContacts = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<LinphoneContact> getContacts(String search) {
|
public List<LinphoneContact> getContacts(String search) {
|
||||||
|
@ -233,11 +216,9 @@ public class ContactsManager extends ContentObserver implements FriendListListen
|
||||||
return searchContactsBegin;
|
return searchContactsBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSipContact(LinphoneContact contact) {
|
private synchronized void addSipContact(LinphoneContact contact) {
|
||||||
synchronized (mSipContacts) {
|
mSipContacts.add(contact);
|
||||||
mSipContacts.add(contact);
|
Collections.sort(mSipContacts);
|
||||||
Collections.sort(mSipContacts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableContactsAccess() {
|
public void enableContactsAccess() {
|
||||||
|
@ -380,7 +361,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
|
||||||
for (Friend lf : friends) {
|
for (Friend lf : friends) {
|
||||||
boolean newContact = ContactsManager.getInstance().refreshSipContact(lf);
|
boolean newContact = ContactsManager.getInstance().refreshSipContact(lf);
|
||||||
if (newContact) {
|
if (newContact) {
|
||||||
for (ContactsUpdatedListener listener : sContactsUpdatedListeners) {
|
for (ContactsUpdatedListener listener : mContactsUpdatedListeners) {
|
||||||
listener.onContactsUpdated();
|
listener.onContactsUpdated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,16 +372,11 @@ public class ContactsManager extends ContentObserver implements FriendListListen
|
||||||
if (mLoadContactTask != null) {
|
if (mLoadContactTask != null) {
|
||||||
mLoadContactTask.cancel(true);
|
mLoadContactTask.cancel(true);
|
||||||
}
|
}
|
||||||
mLoadContactTask = new AsyncContactsLoader();
|
mLoadContactTask = new AsyncContactsLoader(mContext);
|
||||||
|
mContactsFetchedOnce = true;
|
||||||
mLoadContactTask.executeOnExecutor(THREAD_POOL_EXECUTOR);
|
mLoadContactTask.executeOnExecutor(THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void setSipContacts(List<LinphoneContact> c) {
|
|
||||||
synchronized (mSipContacts) {
|
|
||||||
mSipContacts = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void editContact(Context context, LinphoneContact contact, String valueToAdd) {
|
public void editContact(Context context, LinphoneContact contact, String valueToAdd) {
|
||||||
if (context.getResources().getBoolean(R.bool.use_native_contact_editor)) {
|
if (context.getResources().getBoolean(R.bool.use_native_contact_editor)) {
|
||||||
Intent intent = new Intent(Intent.ACTION_EDIT);
|
Intent intent = new Intent(Intent.ACTION_EDIT);
|
||||||
|
@ -415,7 +391,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
|
||||||
}
|
}
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
} else {
|
} else {
|
||||||
LinphoneActivity.instance().editContact(contact);
|
LinphoneActivity.instance().editContact(contact, valueToAdd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,204 +412,4 @@ public class ContactsManager extends ContentObserver implements FriendListListen
|
||||||
LinphoneActivity.instance().addContact(name, valueToAdd);
|
LinphoneActivity.instance().addContact(name, valueToAdd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncContactsData {
|
|
||||||
final List<LinphoneContact> contacts;
|
|
||||||
final List<LinphoneContact> sipContacts;
|
|
||||||
|
|
||||||
AsyncContactsData() {
|
|
||||||
contacts = new ArrayList<>();
|
|
||||||
sipContacts = new ArrayList<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsData> {
|
|
||||||
private HashMap<String, LinphoneContact> mAndroidContactsCache;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPreExecute() {
|
|
||||||
mAndroidContactsCache = new HashMap<>();
|
|
||||||
mContactsFetchedOnce = true;
|
|
||||||
|
|
||||||
if (mContext == null) {
|
|
||||||
mContext = LinphoneService.instance().getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LinphonePreferences.instance() != null
|
|
||||||
&& LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
|
|
||||||
String rls = 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(ContactsManager.this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AsyncContactsData doInBackground(Void... params) {
|
|
||||||
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 {
|
|
||||||
if (friend.getRefKey() != null) {
|
|
||||||
// Friend has a refkey and but no LinphoneContact => represents a
|
|
||||||
// native contact stored in db from a previous version of Linphone,
|
|
||||||
// remove it
|
|
||||||
list.removeFriend(friend);
|
|
||||||
} else {
|
|
||||||
// No refkey so it's a standalone contact
|
|
||||||
contact = new LinphoneContact();
|
|
||||||
contact.setFriend(friend);
|
|
||||||
contact.refresh();
|
|
||||||
data.contacts.add(contact);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c != null) {
|
|
||||||
List<String> nativeIds = new ArrayList<>();
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
if (isCancelled()) return data;
|
|
||||||
|
|
||||||
String id = c.getString(c.getColumnIndex(Data.CONTACT_ID));
|
|
||||||
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"));
|
|
||||||
String lookupKey =
|
|
||||||
c.getString(c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
|
|
||||||
|
|
||||||
LinphoneContact contact = mAndroidContactsCache.get(id);
|
|
||||||
if (contact == null) {
|
|
||||||
nativeIds.add(id);
|
|
||||||
contact = new LinphoneContact();
|
|
||||||
contact.setAndroidId(id);
|
|
||||||
contact.setAndroidLookupKey(lookupKey);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
|
|
||||||
for (FriendList list : lc.getFriendsLists()) {
|
|
||||||
for (Friend friend : list.getFriends()) {
|
|
||||||
if (isCancelled()) return data;
|
|
||||||
|
|
||||||
LinphoneContact contact = (LinphoneContact) friend.getUserData();
|
|
||||||
if (contact != null && contact.isAndroidContact()) {
|
|
||||||
String id = contact.getAndroidId();
|
|
||||||
if (id != null && !nativeIds.contains(id)) {
|
|
||||||
// Has been removed since last fetch
|
|
||||||
mAndroidContactsCache.remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nativeIds.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (LinphoneContact contact : mAndroidContactsCache.values()) {
|
|
||||||
if (isCancelled()) return data;
|
|
||||||
|
|
||||||
boolean hideContactsWithoutPresence =
|
|
||||||
mContext.getResources()
|
|
||||||
.getBoolean(R.bool.hide_sip_contacts_without_presence);
|
|
||||||
if (contact.hasAddress()) {
|
|
||||||
if (contact.getFullName() == null) {
|
|
||||||
for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) {
|
|
||||||
if (noa.isSIPAddress()) {
|
|
||||||
contact.setFullName(
|
|
||||||
LinphoneUtils.getAddressDisplayName(noa.getValue()));
|
|
||||||
Log.w(
|
|
||||||
"[Contacts Manager] Couldn't find a display name for contact "
|
|
||||||
+ contact.getFullName()
|
|
||||||
+ ", used SIP address display name / username instead...");
|
|
||||||
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 {
|
|
||||||
data.sipContacts.add(contact);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data.contacts.add(contact);
|
|
||||||
}
|
|
||||||
mAndroidContactsCache.clear();
|
|
||||||
|
|
||||||
Collections.sort(data.contacts);
|
|
||||||
Collections.sort(data.sipContacts);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(AsyncContactsData data) {
|
|
||||||
for (ContactsUpdatedListener listener : sContactsUpdatedListeners) {
|
|
||||||
listener.onContactsUpdated();
|
|
||||||
}
|
|
||||||
for (LinphoneContact contact : data.contacts) {
|
|
||||||
contact.createOrUpdateFriendFromNativeContact();
|
|
||||||
}
|
|
||||||
|
|
||||||
setContacts(data.contacts);
|
|
||||||
setSipContacts(data.sipContacts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ public class HistoryFragment extends Fragment
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
ContactsManager.addContactsListener(this);
|
ContactsManager.getInstance().addContactsListener(this);
|
||||||
|
|
||||||
if (LinphoneActivity.isInstanciated()) {
|
if (LinphoneActivity.isInstanciated()) {
|
||||||
LinphoneActivity.instance().selectMenu(FragmentsAvailable.HISTORY_LIST);
|
LinphoneActivity.instance().selectMenu(FragmentsAvailable.HISTORY_LIST);
|
||||||
|
@ -173,7 +173,7 @@ public class HistoryFragment extends Fragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
ContactsManager.removeContactsListener(this);
|
ContactsManager.getInstance().removeContactsListener(this);
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue