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.content.Intent;
import android.os.Build; import android.os.Build;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import java.util.ArrayList;
import org.linphone.call.CallActivity; import org.linphone.call.CallActivity;
import org.linphone.call.CallIncomingActivity; import org.linphone.call.CallIncomingActivity;
import org.linphone.call.CallOutgoingActivity; import org.linphone.call.CallOutgoingActivity;
import org.linphone.compatibility.Compatibility; import org.linphone.compatibility.Compatibility;
import org.linphone.contacts.ContactsManager; import org.linphone.contacts.ContactsManager;
import org.linphone.core.Call; import org.linphone.core.Call;
import org.linphone.core.ConfiguringState;
import org.linphone.core.Core; import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub; import org.linphone.core.CoreListenerStub;
import org.linphone.core.Factory; import org.linphone.core.Factory;
import org.linphone.core.GlobalState;
import org.linphone.core.LogLevel; import org.linphone.core.LogLevel;
import org.linphone.core.LoggingService; import org.linphone.core.LoggingService;
import org.linphone.core.LoggingServiceListener; import org.linphone.core.LoggingServiceListener;
@ -79,6 +82,7 @@ public class LinphoneContext {
private LinphoneManager mLinphoneManager; private LinphoneManager mLinphoneManager;
private ContactsManager mContactsManager; private ContactsManager mContactsManager;
private Class<? extends Activity> mIncomingReceivedActivity = CallIncomingActivity.class; private Class<? extends Activity> mIncomingReceivedActivity = CallIncomingActivity.class;
private final ArrayList<CoreStartedListener> mCoreStartedListeners;
public static boolean isReady() { public static boolean isReady() {
return sInstance != null; return sInstance != null;
@ -90,6 +94,7 @@ public class LinphoneContext {
public LinphoneContext(Context context) { public LinphoneContext(Context context) {
mContext = context; mContext = context;
mCoreStartedListeners = new ArrayList<>();
LinphonePreferences.instance().setContext(context); LinphonePreferences.instance().setContext(context);
Factory.instance().setLogCollectionPath(context.getFilesDir().getAbsolutePath()); Factory.instance().setLogCollectionPath(context.getFilesDir().getAbsolutePath());
@ -114,9 +119,35 @@ public class LinphoneContext {
mListener = mListener =
new CoreListenerStub() { 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 @Override
public void onCallStateChanged( public void onCallStateChanged(
Core core, Call call, Call.State state, String message) { 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)) { if (mContext.getResources().getBoolean(R.bool.enable_call_notification)) {
mNotificationManager.displayCallNotification(call); mNotificationManager.displayCallNotification(call);
} }
@ -161,8 +192,7 @@ public class LinphoneContext {
public void start(boolean isPush) { public void start(boolean isPush) {
Log.i("[Context] Starting"); Log.i("[Context] Starting");
mLinphoneManager.startLibLinphone(isPush); mLinphoneManager.startLibLinphone(isPush, mListener);
LinphoneManager.getCore().addListener(mListener);
mNotificationManager.onCoreReady(); mNotificationManager.onCoreReady();
@ -176,6 +206,7 @@ public class LinphoneContext {
if (mContactsManager.hasReadContactsAccess()) { if (mContactsManager.hasReadContactsAccess()) {
mContactsManager.enableContactsAccess(); mContactsManager.enableContactsAccess();
} }
mContactsManager.initializeContactManager(); mContactsManager.initializeContactManager();
} }
@ -236,6 +267,14 @@ public class LinphoneContext {
return mContactsManager; return mContactsManager;
} }
public void addCoreStartedListener(CoreStartedListener listener) {
mCoreStartedListeners.add(listener);
}
public void removeCoreStartedListener(CoreStartedListener listener) {
mCoreStartedListeners.remove(listener);
}
/* Log device related information */ /* Log device related information */
private void dumpDeviceInformation() { private void dumpDeviceInformation() {
@ -285,4 +324,8 @@ public class LinphoneContext {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent); 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.AccountCreatorListenerStub;
import org.linphone.core.Call; import org.linphone.core.Call;
import org.linphone.core.Call.State; import org.linphone.core.Call.State;
import org.linphone.core.ConfiguringState;
import org.linphone.core.Core; import org.linphone.core.Core;
import org.linphone.core.CoreListener;
import org.linphone.core.CoreListenerStub; import org.linphone.core.CoreListenerStub;
import org.linphone.core.Factory; import org.linphone.core.Factory;
import org.linphone.core.FriendList; import org.linphone.core.FriendList;
import org.linphone.core.GlobalState;
import org.linphone.core.PresenceActivity; import org.linphone.core.PresenceActivity;
import org.linphone.core.PresenceBasicStatus; import org.linphone.core.PresenceBasicStatus;
import org.linphone.core.PresenceModel; import org.linphone.core.PresenceModel;
@ -160,37 +159,6 @@ public class LinphoneManager implements SensorEventListener {
mCoreListener = mCoreListener =
new CoreListenerStub() { 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") @SuppressLint("Wakelock")
@Override @Override
public void onCallStateChanged( public void onCallStateChanged(
@ -198,7 +166,7 @@ public class LinphoneManager implements SensorEventListener {
final Call call, final Call call,
final State state, final State state,
final String message) { final String message) {
Log.i("[Manager] New call state [", state, "]"); Log.i("[Manager] Call state is [", state, "]");
if (state == State.IncomingReceived if (state == State.IncomingReceived
&& !call.equals(core.getCurrentCall())) { && !call.equals(core.getCurrentCall())) {
if (call.getReplacedCall() != null) { 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 { try {
mCore = mCore =
Factory.instance() Factory.instance()
@ -437,6 +405,7 @@ public class LinphoneManager implements SensorEventListener {
mPrefs.getLinphoneDefaultConfig(), mPrefs.getLinphoneDefaultConfig(),
mPrefs.getLinphoneFactoryConfig(), mPrefs.getLinphoneFactoryConfig(),
mContext); mContext);
mCore.addListener(listener);
mCore.addListener(mCoreListener); mCore.addListener(mCoreListener);
if (isPush) { 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*/ /*use schedule instead of scheduleAtFixedRate to avoid iterate from being call in burst after cpu wake up*/
mTimer = new Timer("Linphone scheduler"); mTimer = new Timer("Linphone scheduler");
mTimer.schedule(lTask, 0, 20); mTimer.schedule(lTask, 0, 20);
initLiblinphone(mCore);
} catch (Exception e) { } catch (Exception e) {
Log.e(e, "[Manager] Cannot start linphone"); 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) { protected AsyncContactsData doInBackground(Void... params) {
Log.i("[Contacts Manager] Background synchronization started"); 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<>(); HashMap<String, LinphoneContact> androidContactsCache = new HashMap<>();
AsyncContactsData data = new AsyncContactsData(); AsyncContactsData data = new AsyncContactsData();
List<String> nativeIds = new ArrayList<>(); List<String> nativeIds = new ArrayList<>();
@ -110,9 +95,12 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
} }
LinphoneContact contact = (LinphoneContact) friend.getUserData(); 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) { if (contact != null) {
contact.clearAddresses();
if (contact.getAndroidId() != null) { if (contact.getAndroidId() != null) {
contact.clearAddresses();
androidContactsCache.put(contact.getAndroidId(), contact); androidContactsCache.put(contact.getAndroidId(), contact);
nativeIds.add(contact.getAndroidId()); nativeIds.add(contact.getAndroidId());
} }
@ -134,35 +122,51 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
} }
} }
if (c != null) { if (ContactsManager.getInstance().hasReadContactsAccess()) {
Log.i("[Contacts Manager] Found " + c.getCount() + " entries in cursor"); String selection = null;
while (c.moveToNext()) { if (mContext.getResources().getBoolean(R.bool.fetch_contacts_from_default_directory)) {
if (isCancelled()) { Log.i("[Contacts Manager] Only fetching contacts in default directory");
Log.w("[Contacts Manager] Task cancelled"); selection = ContactsContract.Data.IN_DEFAULT_DIRECTORY + " == 1";
return data; }
}
Cursor c =
String id = c.getString(c.getColumnIndex(ContactsContract.Data.CONTACT_ID)); mContext.getContentResolver()
boolean starred = .query(
c.getInt(c.getColumnIndex(ContactsContract.Contacts.STARRED)) == 1; ContactsContract.Data.CONTENT_URI,
PROJECTION,
LinphoneContact contact = androidContactsCache.get(id); selection,
if (contact == null) { null,
Log.d( null);
"[Contacts Manager] Creating LinphoneContact with native ID " if (c != null) {
+ id Log.i("[Contacts Manager] Found " + c.getCount() + " entries in cursor");
+ ", favorite flag is " while (c.moveToNext()) {
+ starred); if (isCancelled()) {
nativeIds.add(id); Log.w("[Contacts Manager] Task cancelled");
contact = new LinphoneContact(); return data;
contact.setAndroidId(id); }
contact.setIsFavourite(starred);
androidContactsCache.put(id, contact); String id = c.getString(c.getColumnIndex(ContactsContract.Data.CONTACT_ID));
} boolean starred =
c.getInt(c.getColumnIndex(ContactsContract.Contacts.STARRED)) == 1;
contact.syncValuesFromAndroidCusor(c);
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(); FriendList[] friendLists = core.getFriendsLists();
for (FriendList list : friendLists) { for (FriendList list : friendLists) {
@ -188,7 +192,13 @@ class AsyncContactsLoader extends AsyncTask<Void, Void, AsyncContactsLoader.Asyn
} }
Collection<LinphoneContact> contacts = androidContactsCache.values(); 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) { for (LinphoneContact contact : contacts) {
if (isCancelled()) { if (isCancelled()) {
Log.w("[Contacts Manager] Task cancelled"); 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.core.tools.Log;
import org.linphone.settings.LinphonePreferences; 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 List<LinphoneContact> mContacts, mSipContacts;
private final ArrayList<ContactsUpdatedListener> mContactsUpdatedListeners; private final ArrayList<ContactsUpdatedListener> mContactsUpdatedListeners;
private MagicSearch mMagicSearch; private MagicSearch mMagicSearch;
@ -79,6 +80,8 @@ public class ContactsManager extends ContentObserver implements FriendListListen
mMagicSearch = LinphoneManager.getCore().createMagicSearch(); mMagicSearch = LinphoneManager.getCore().createMagicSearch();
mMagicSearch.setLimitedSearch(false); // Do not limit the number of results mMagicSearch.setLimitedSearch(false); // Do not limit the number of results
} }
LinphoneContext.instance().addCoreStartedListener(this);
} }
public void addContactsListener(ContactsUpdatedListener listener) { public void addContactsListener(ContactsUpdatedListener listener) {
@ -104,6 +107,13 @@ public class ContactsManager extends ContentObserver implements FriendListListen
fetchContactsAsync(); 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() { public synchronized List<LinphoneContact> getContacts() {
return mContacts; return mContacts;
} }
@ -122,6 +132,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen
public void destroy() { public void destroy() {
mContext.getContentResolver().unregisterContentObserver(this); mContext.getContentResolver().unregisterContentObserver(this);
LinphoneContext.instance().removeCoreStartedListener(this);
if (mLoadContactTask != null) { if (mLoadContactTask != null) {
mLoadContactTask.cancel(true); mLoadContactTask.cancel(true);
@ -149,10 +160,12 @@ public class ContactsManager extends ContentObserver implements FriendListListen
if (mLoadContactTask != null) { if (mLoadContactTask != null) {
mLoadContactTask.cancel(true); mLoadContactTask.cancel(true);
} }
if (!hasReadContactsAccess()) { if (!hasReadContactsAccess()) {
Log.w("[Contacts Manager] Can't fetch contact without READ permission"); Log.w(
return; "[Contacts Manager] Can't fetch native contacts without READ_CONTACTS permission");
} }
mLoadContactTask = new AsyncContactsLoader(mContext); mLoadContactTask = new AsyncContactsLoader(mContext);
mContactsFetchedOnce = true; mContactsFetchedOnce = true;
mLoadContactTask.executeOnExecutor(THREAD_POOL_EXECUTOR); 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() { private void makeContactAccountVisible() {

View file

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