Fixed empty history & missing contacts when fetched through remote provisionning

This commit is contained in:
Sylvain Berfini 2019-11-13 11:18:15 +01:00
parent cdf8b55d06
commit ba6a3c70bb
5 changed files with 144 additions and 97 deletions

View file

@ -26,15 +26,18 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.provider.ContactsContract;
import java.util.ArrayList;
import org.linphone.call.CallActivity;
import org.linphone.call.CallIncomingActivity;
import org.linphone.call.CallOutgoingActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager;
import org.linphone.core.Call;
import org.linphone.core.ConfiguringState;
import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.Factory;
import org.linphone.core.GlobalState;
import org.linphone.core.LogLevel;
import org.linphone.core.LoggingService;
import org.linphone.core.LoggingServiceListener;
@ -79,6 +82,7 @@ public class LinphoneContext {
private LinphoneManager mLinphoneManager;
private ContactsManager mContactsManager;
private Class<? extends Activity> mIncomingReceivedActivity = CallIncomingActivity.class;
private final ArrayList<CoreStartedListener> mCoreStartedListeners;
public static boolean isReady() {
return sInstance != null;
@ -90,6 +94,7 @@ public class LinphoneContext {
public LinphoneContext(Context context) {
mContext = context;
mCoreStartedListeners = new ArrayList<>();
LinphonePreferences.instance().setContext(context);
Factory.instance().setLogCollectionPath(context.getFilesDir().getAbsolutePath());
@ -114,9 +119,35 @@ public class LinphoneContext {
mListener =
new CoreListenerStub() {
@Override
public void onGlobalStateChanged(Core core, GlobalState state, String message) {
Log.i("[Context] Global state is [", state, "]");
if (state == GlobalState.On) {
for (CoreStartedListener listener : mCoreStartedListeners) {
listener.onCoreStarted();
}
}
}
@Override
public void onConfiguringStatus(
Core core, ConfiguringState status, String message) {
Log.i("[Context] Configuring state is [", status, "]");
if (status == ConfiguringState.Successful) {
LinphonePreferences.instance()
.setPushNotificationEnabled(
LinphonePreferences.instance()
.isPushNotificationEnabled());
}
}
@Override
public void onCallStateChanged(
Core core, Call call, Call.State state, String message) {
Log.i("[Context] Call state is [", state, "]");
if (mContext.getResources().getBoolean(R.bool.enable_call_notification)) {
mNotificationManager.displayCallNotification(call);
}
@ -161,8 +192,7 @@ public class LinphoneContext {
public void start(boolean isPush) {
Log.i("[Context] Starting");
mLinphoneManager.startLibLinphone(isPush);
LinphoneManager.getCore().addListener(mListener);
mLinphoneManager.startLibLinphone(isPush, mListener);
mNotificationManager.onCoreReady();
@ -176,6 +206,7 @@ public class LinphoneContext {
if (mContactsManager.hasReadContactsAccess()) {
mContactsManager.enableContactsAccess();
}
mContactsManager.initializeContactManager();
}
@ -236,6 +267,14 @@ public class LinphoneContext {
return mContactsManager;
}
public void addCoreStartedListener(CoreStartedListener listener) {
mCoreStartedListeners.add(listener);
}
public void removeCoreStartedListener(CoreStartedListener listener) {
mCoreStartedListeners.remove(listener);
}
/* Log device related information */
private void dumpDeviceInformation() {
@ -285,4 +324,8 @@ public class LinphoneContext {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
public interface CoreStartedListener {
void onCoreStarted();
}
}

View file

@ -51,12 +51,11 @@ import org.linphone.core.AccountCreator;
import org.linphone.core.AccountCreatorListenerStub;
import org.linphone.core.Call;
import org.linphone.core.Call.State;
import org.linphone.core.ConfiguringState;
import org.linphone.core.Core;
import org.linphone.core.CoreListener;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.Factory;
import org.linphone.core.FriendList;
import org.linphone.core.GlobalState;
import org.linphone.core.PresenceActivity;
import org.linphone.core.PresenceBasicStatus;
import org.linphone.core.PresenceModel;
@ -160,37 +159,6 @@ public class LinphoneManager implements SensorEventListener {
mCoreListener =
new CoreListenerStub() {
@Override
public void onGlobalStateChanged(
final Core core, final GlobalState state, final String message) {
Log.i("New global state [", state, "]");
if (state == GlobalState.On) {
try {
initLiblinphone(core);
} catch (IllegalArgumentException iae) {
Log.e(
"[Manager] Global State Changed Illegal Argument Exception: "
+ iae);
}
}
}
@Override
public void onConfiguringStatus(
Core core, ConfiguringState state, String message) {
Log.d(
"[Manager] Remote provisioning status = "
+ state.toString()
+ " ("
+ message
+ ")");
LinphonePreferences prefs = LinphonePreferences.instance();
if (state == ConfiguringState.Successful) {
prefs.setPushNotificationEnabled(prefs.isPushNotificationEnabled());
}
}
@SuppressLint("Wakelock")
@Override
public void onCallStateChanged(
@ -198,7 +166,7 @@ public class LinphoneManager implements SensorEventListener {
final Call call,
final State state,
final String message) {
Log.i("[Manager] New call state [", state, "]");
Log.i("[Manager] Call state is [", state, "]");
if (state == State.IncomingReceived
&& !call.equals(core.getCurrentCall())) {
if (call.getReplacedCall() != null) {
@ -429,7 +397,7 @@ public class LinphoneManager implements SensorEventListener {
}
}
public synchronized void startLibLinphone(boolean isPush) {
public synchronized void startLibLinphone(boolean isPush, CoreListener listener) {
try {
mCore =
Factory.instance()
@ -437,6 +405,7 @@ public class LinphoneManager implements SensorEventListener {
mPrefs.getLinphoneDefaultConfig(),
mPrefs.getLinphoneFactoryConfig(),
mContext);
mCore.addListener(listener);
mCore.addListener(mCoreListener);
if (isPush) {
@ -466,6 +435,8 @@ public class LinphoneManager implements SensorEventListener {
/*use schedule instead of scheduleAtFixedRate to avoid iterate from being call in burst after cpu wake up*/
mTimer = new Timer("Linphone scheduler");
mTimer.schedule(lTask, 0, 20);
initLiblinphone(mCore);
} catch (Exception e) {
Log.e(e, "[Manager] Cannot start linphone");
}

View file

@ -79,21 +79,6 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
protected AsyncContactsData doInBackground(Void... params) {
Log.i("[Contacts Manager] Background synchronization started");
String selection = null;
if (mContext.getResources().getBoolean(R.bool.fetch_contacts_from_default_directory)) {
Log.i("[Contacts Manager] Only fetching contacts in default directory");
selection = ContactsContract.Data.IN_DEFAULT_DIRECTORY + " == 1";
}
Cursor c =
mContext.getContentResolver()
.query(
ContactsContract.Data.CONTENT_URI,
PROJECTION,
selection,
null,
null);
HashMap<String, LinphoneContact> androidContactsCache = new HashMap<>();
AsyncContactsData data = new AsyncContactsData();
List<String> nativeIds = new ArrayList<>();
@ -110,9 +95,12 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
}
LinphoneContact contact = (LinphoneContact) friend.getUserData();
// A previously fetched friend from rc file will have a user data,
// so the next fetches won't add it in data.contacts
// and thus the "new friends" count in log will be different /!\
if (contact != null) {
contact.clearAddresses();
if (contact.getAndroidId() != null) {
contact.clearAddresses();
androidContactsCache.put(contact.getAndroidId(), contact);
nativeIds.add(contact.getAndroidId());
}
@ -134,35 +122,51 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
}
}
if (c != null) {
Log.i("[Contacts Manager] Found " + c.getCount() + " entries in cursor");
while (c.moveToNext()) {
if (isCancelled()) {
Log.w("[Contacts Manager] Task cancelled");
return data;
}
String id = c.getString(c.getColumnIndex(ContactsContract.Data.CONTACT_ID));
boolean starred =
c.getInt(c.getColumnIndex(ContactsContract.Contacts.STARRED)) == 1;
LinphoneContact contact = androidContactsCache.get(id);
if (contact == null) {
Log.d(
"[Contacts Manager] Creating LinphoneContact with native ID "
+ id
+ ", favorite flag is "
+ starred);
nativeIds.add(id);
contact = new LinphoneContact();
contact.setAndroidId(id);
contact.setIsFavourite(starred);
androidContactsCache.put(id, contact);
}
contact.syncValuesFromAndroidCusor(c);
if (ContactsManager.getInstance().hasReadContactsAccess()) {
String selection = null;
if (mContext.getResources().getBoolean(R.bool.fetch_contacts_from_default_directory)) {
Log.i("[Contacts Manager] Only fetching contacts in default directory");
selection = ContactsContract.Data.IN_DEFAULT_DIRECTORY + " == 1";
}
Cursor c =
mContext.getContentResolver()
.query(
ContactsContract.Data.CONTENT_URI,
PROJECTION,
selection,
null,
null);
if (c != null) {
Log.i("[Contacts Manager] Found " + c.getCount() + " entries in cursor");
while (c.moveToNext()) {
if (isCancelled()) {
Log.w("[Contacts Manager] Task cancelled");
return data;
}
String id = c.getString(c.getColumnIndex(ContactsContract.Data.CONTACT_ID));
boolean starred =
c.getInt(c.getColumnIndex(ContactsContract.Contacts.STARRED)) == 1;
LinphoneContact contact = androidContactsCache.get(id);
if (contact == null) {
Log.d(
"[Contacts Manager] Creating LinphoneContact with native ID "
+ id
+ ", favorite flag is "
+ starred);
nativeIds.add(id);
contact = new LinphoneContact();
contact.setAndroidId(id);
contact.setIsFavourite(starred);
androidContactsCache.put(id, contact);
}
contact.syncValuesFromAndroidCusor(c);
}
c.close();
}
c.close();
FriendList[] friendLists = core.getFriendsLists();
for (FriendList list : friendLists) {
@ -188,7 +192,13 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
}
Collection<LinphoneContact> contacts = androidContactsCache.values();
Log.i("[Contacts Manager] Found " + contacts.size() + " contacts");
// New friends count will be 0 after the first contacts fetch
Log.i(
"[Contacts Manager] Found "
+ contacts.size()
+ " native contacts plus "
+ data.contacts.size()
+ " new friends in the configuration file");
for (LinphoneContact contact : contacts) {
if (isCancelled()) {
Log.w("[Contacts Manager] Task cancelled");

View file

@ -55,7 +55,8 @@ import org.linphone.core.ProxyConfig;
import org.linphone.core.tools.Log;
import org.linphone.settings.LinphonePreferences;
public class ContactsManager extends ContentObserver implements FriendListListener {
public class ContactsManager extends ContentObserver
implements FriendListListener, LinphoneContext.CoreStartedListener {
private List<LinphoneContact> mContacts, mSipContacts;
private final ArrayList<ContactsUpdatedListener> mContactsUpdatedListeners;
private MagicSearch mMagicSearch;
@ -79,6 +80,8 @@ public class ContactsManager extends ContentObserver implements FriendListListen
mMagicSearch = LinphoneManager.getCore().createMagicSearch();
mMagicSearch.setLimitedSearch(false); // Do not limit the number of results
}
LinphoneContext.instance().addCoreStartedListener(this);
}
public void addContactsListener(ContactsUpdatedListener listener) {
@ -104,6 +107,13 @@ public class ContactsManager extends ContentObserver implements FriendListListen
fetchContactsAsync();
}
@Override
public void onCoreStarted() {
// Core has been started, fetch contacts again in case there are some
// in the configuration file or remote provisioning
fetchContactsAsync();
}
public synchronized List<LinphoneContact> getContacts() {
return mContacts;
}
@ -122,6 +132,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
public void destroy() {
mContext.getContentResolver().unregisterContentObserver(this);
LinphoneContext.instance().removeCoreStartedListener(this);
if (mLoadContactTask != null) {
mLoadContactTask.cancel(true);
@ -149,10 +160,12 @@ public class ContactsManager extends ContentObserver implements FriendListListen
if (mLoadContactTask != null) {
mLoadContactTask.cancel(true);
}
if (!hasReadContactsAccess()) {
Log.w("[Contacts Manager] Can't fetch contact without READ permission");
return;
Log.w(
"[Contacts Manager] Can't fetch native contacts without READ_CONTACTS permission");
}
mLoadContactTask = new AsyncContactsLoader(mContext);
mContactsFetchedOnce = true;
mLoadContactTask.executeOnExecutor(THREAD_POOL_EXECUTOR);
@ -264,10 +277,6 @@ public class ContactsManager extends ContentObserver implements FriendListListen
}
}
}
if (mContext != null && getContacts().isEmpty() && hasReadContactsAccess()) {
fetchContactsAsync();
}
}
private void makeContactAccountVisible() {

View file

@ -35,6 +35,7 @@ import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.linphone.LinphoneContext;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.contacts.ContactsManager;
@ -51,7 +52,8 @@ public class HistoryFragment extends Fragment
OnItemClickListener,
HistoryViewHolder.ClickListener,
ContactsUpdatedListener,
SelectableHelper.DeleteListener {
SelectableHelper.DeleteListener,
LinphoneContext.CoreStartedListener {
private RecyclerView mHistoryList;
private TextView mNoCallHistory, mNoMissedCallHistory;
private ImageView mMissedCalls, mAllCalls;
@ -101,19 +103,16 @@ public class HistoryFragment extends Fragment
public void onResume() {
super.onResume();
ContactsManager.getInstance().addContactsListener(this);
LinphoneContext.instance().addCoreStartedListener(this);
mLogs = Arrays.asList(LinphoneManager.getCore().getCallLogs());
hideHistoryListAndDisplayMessageIfEmpty();
mHistoryAdapter =
new HistoryAdapter((HistoryActivity) getActivity(), mLogs, this, mSelectionHelper);
mHistoryList.setAdapter(mHistoryAdapter);
mSelectionHelper.setAdapter(mHistoryAdapter);
mSelectionHelper.setDialogMessage(R.string.call_log_delete_dialog);
reloadData();
}
@Override
public void onPause() {
ContactsManager.getInstance().removeContactsListener(this);
LinphoneContext.instance().removeCoreStartedListener(this);
super.onPause();
}
@ -125,6 +124,11 @@ public class HistoryFragment extends Fragment
}
}
@Override
public void onCoreStarted() {
reloadData();
}
@Override
public void onClick(View v) {
int id = v.getId();
@ -218,6 +222,16 @@ public class HistoryFragment extends Fragment
}
}
private void reloadData() {
mLogs = Arrays.asList(LinphoneManager.getCore().getCallLogs());
hideHistoryListAndDisplayMessageIfEmpty();
mHistoryAdapter =
new HistoryAdapter((HistoryActivity) getActivity(), mLogs, this, mSelectionHelper);
mHistoryList.setAdapter(mHistoryAdapter);
mSelectionHelper.setAdapter(mHistoryAdapter);
mSelectionHelper.setDialogMessage(R.string.call_log_delete_dialog);
}
private void removeNotMissedCallsFromLogs() {
if (mOnlyDisplayMissedCalls) {
List<CallLog> missedCalls = new ArrayList<>();